QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgslayoutitemlegend.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutitemlegend.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#include <limits>
18
19#include "qgslayoutitemlegend.h"
21#include "qgslayoutitemmap.h"
22#include "qgslayoutmodel.h"
23#include "qgslayertree.h"
24#include "qgslayertreemodel.h"
25#include "qgslegendrenderer.h"
26#include "qgslegendstyle.h"
27#include "qgslogger.h"
28#include "qgsmapsettings.h"
29#include "qgsproject.h"
30#include "qgssymbollayerutils.h"
31#include "qgslayertreeutils.h"
32#include "qgslayoututils.h"
33#include "qgslayout.h"
36#include "qgsvectorlayer.h"
41
42#include <QDomDocument>
43#include <QDomElement>
44#include <QPainter>
46
48 : QgsLayoutItem( layout )
49 , mLegendModel( new QgsLegendModel( layout->project()->layerTreeRoot(), this ) )
50{
51#if 0 //no longer required?
52 connect( &layout->atlasComposition(), &QgsAtlasComposition::renderEnded, this, &QgsLayoutItemLegend::onAtlasEnded );
53#endif
54
55 mTitle = mSettings.title();
56
57 connect( mLegendModel.get(), &QgsLayerTreeModel::hitTestStarted, this, [ = ] { emit backgroundTaskCountChanged( 1 ); } );
58 connect( mLegendModel.get(), &QgsLayerTreeModel::hitTestCompleted, this, [ = ]
59 {
60 adjustBoxSize();
61 emit backgroundTaskCountChanged( 0 );
62 } );
63
64 // Connect to the main layertreeroot.
65 // It serves in "auto update mode" as a medium between the main app legend and this one
66 connect( mLayout->project()->layerTreeRoot(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayoutItemLegend::nodeCustomPropertyChanged );
67
68 // If project colors change, we need to redraw legend, as legend symbols may rely on project colors
69 connect( mLayout->project(), &QgsProject::projectColorsChanged, this, [ = ]
70 {
71 invalidateCache();
72 update();
73 } );
74 connect( mLegendModel.get(), &QgsLegendModel::refreshLegend, this, [ = ]
75 {
76 // NOTE -- we do NOT connect to ::refresh here, as we don't want to trigger the call to onAtlasFeature() which sets mFilterAskedForUpdate to true,
77 // causing an endless loop.
78
79 // TODO -- the call to QgsLayoutItem::refresh() is probably NOT required!
80 QgsLayoutItem::refresh();
81
82 // (this one is definitely required)
83 clearLegendCachedData();
84 } );
85}
86
88{
89 return new QgsLayoutItemLegend( layout );
90}
91
93{
95}
96
98{
99 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemLegend.svg" ) );
100}
101
102QgsLayoutItem::Flags QgsLayoutItemLegend::itemFlags() const
103{
105}
106
107void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
108{
109 if ( !painter )
110 return;
111
112 if ( mFilterAskedForUpdate )
113 {
114 mFilterAskedForUpdate = false;
115 doUpdateFilterByMap();
116 }
117
118 if ( mLayout )
119 {
120 if ( !mLayout->renderContext().isPreviewRender() && mLegendModel->hitTestInProgress() )
121 {
122 mLegendModel->waitForHitTestBlocking();
123 }
124 }
125
126 const int dpi = painter->device()->logicalDpiX();
127 const double dotsPerMM = dpi / 25.4;
128
129 if ( mLayout )
130 {
132 // no longer required, but left set for api stability
134 mSettings.setDpi( dpi );
136 }
137 if ( mMap && mLayout )
138 {
140 // no longer required, but left set for api stability
141 mSettings.setMmPerMapUnit( mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), Qgis::LayoutUnit::Millimeters ).length() );
143
144 // use a temporary QgsMapSettings to find out real map scale
145 const QSizeF mapSizePixels = QSizeF( mMap->rect().width() * dotsPerMM, mMap->rect().height() * dotsPerMM );
146 const QgsRectangle mapExtent = mMap->extent();
147
148 const QgsMapSettings ms = mMap->mapSettings( mapExtent, mapSizePixels, dpi, false );
149
150 // no longer required, but left set for api stability
152 mSettings.setMapScale( ms.scale() );
154 }
155 mInitialMapScaleCalculated = true;
156
157 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
158 legendRenderer.setLegendSize( mForceResize && mSizeToContents ? QSize() : rect().size() );
159
160 const QPointF oldPos = pos();
161
162 //adjust box if width or height is too small
163 if ( mSizeToContents )
164 {
165 QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter )
167
168 const QSizeF size = legendRenderer.minimumSize( &context );
169 if ( mForceResize )
170 {
171 mForceResize = false;
172
173 //set new rect, respecting position mode and data defined size/position
174 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
175 attemptResize( newSize );
176 }
177 else if ( size.height() > rect().height() || size.width() > rect().width() )
178 {
179 //need to resize box
180 QSizeF targetSize = rect().size();
181 if ( size.height() > targetSize.height() )
182 targetSize.setHeight( size.height() );
183 if ( size.width() > targetSize.width() )
184 targetSize.setWidth( size.width() );
185
186 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( targetSize, sizeWithUnits().units() );
187 //set new rect, respecting position mode and data defined size/position
188 attemptResize( newSize );
189 }
190 }
191
192 // attemptResize may change the legend position and would call setPos
193 // BUT the position is actually changed for the next draw, so we need to translate of the difference
194 // between oldPos and newPos
195 // the issue doesn't appear in desktop rendering but only in export because in the first one,
196 // Qt triggers a redraw on position change
197 painter->save();
198 painter->translate( pos() - oldPos );
199 QgsLayoutItem::paint( painter, itemStyle, pWidget );
200 painter->restore();
201}
202
204{
205 if ( !mMapUuid.isEmpty() )
206 {
207 setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) ) );
208 }
209
210 if ( !mFilterByMapUuids.isEmpty() )
211 {
212 QList< QgsLayoutItemMap * > maps;
213 maps.reserve( mFilterByMapUuids.size() );
214 for ( const QString &uuid : std::as_const( mFilterByMapUuids ) )
215 {
216 if ( QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( uuid, true ) ) )
217 {
218 maps << map;
219 }
220 }
221 setFilterByMapItems( maps );
222 }
223}
224
226{
228 clearLegendCachedData();
229 onAtlasFeature();
230}
231
233{
234 clearLegendCachedData();
236}
237
239{
240 QPainter *painter = context.renderContext().painter();
241
242 QgsRenderContext rc = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter, context.renderContext().scaleFactor() * 25.4 )
244
246
247 const QgsScopedQPainterState painterState( painter );
248
249 // painter is scaled to dots, so scale back to layout units
250 painter->scale( rc.scaleFactor(), rc.scaleFactor() );
251
252 painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
253
254 if ( !mSizeToContents )
255 {
256 // set a clip region to crop out parts of legend which don't fit
257 const QRectF thisPaintRect = QRectF( 0, 0, rect().width(), rect().height() );
258 painter->setClipRect( thisPaintRect );
259 }
260
261 if ( mLayout )
262 {
263 // no longer required, but left for API compatibility
265 mSettings.setDpi( mLayout->renderContext().dpi() );
267 }
268
269 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
270 legendRenderer.setLegendSize( rect().size() );
271
272 legendRenderer.drawLegend( rc );
273}
274
276{
277 if ( !mSizeToContents )
278 return;
279
280 if ( !mInitialMapScaleCalculated )
281 {
282 // this is messy - but until we have painted the item we have no knowledge of the current DPI
283 // and so cannot correctly calculate the map scale. This results in incorrect size calculations
284 // for marker symbols with size in map units, causing the legends to initially expand to huge
285 // sizes if we attempt to calculate the box size first.
286 return;
287 }
288
289 QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, nullptr ) :
291
292 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
293 const QSizeF size = legendRenderer.minimumSize( &context );
294 QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ), 2 );
295 if ( size.isValid() )
296 {
297 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
298 //set new rect, respecting position mode and data defined size/position
299 attemptResize( newSize );
300 }
301}
302
304{
305 mSizeToContents = enabled;
306}
307
309{
310 return mSizeToContents;
311}
312
313void QgsLayoutItemLegend::setCustomLayerTree( QgsLayerTree *rootGroup )
314{
315 mLegendModel->setRootGroup( rootGroup ? rootGroup : ( mLayout ? mLayout->project()->layerTreeRoot() : nullptr ) );
316
317 mCustomLayerTree.reset( rootGroup );
318}
319
320
322{
323 if ( autoUpdate == autoUpdateModel() )
324 return;
325
326 setCustomLayerTree( autoUpdate ? nullptr : mLayout->project()->layerTreeRoot()->clone() );
328 updateFilterByMap( false );
329}
330
331void QgsLayoutItemLegend::nodeCustomPropertyChanged( QgsLayerTreeNode *, const QString &key )
332{
333 if ( key == QLatin1String( "cached_name" ) )
334 return;
335
336 if ( autoUpdateModel() )
337 {
338 // in "auto update" mode, some parameters on the main app legend may have been changed (expression filtering)
339 // we must then call updateItem to reflect the changes
340 updateFilterByMap( false );
341 }
342}
343
345{
346 return !mCustomLayerTree;
347}
348
350{
351 if ( mLegendFilterByMap == enabled )
352 return;
353
354 mLegendFilterByMap = enabled;
355 updateFilterByMap( false );
356}
357
358void QgsLayoutItemLegend::setTitle( const QString &t )
359{
360 mTitle = t;
361 mSettings.setTitle( t );
362
363 if ( mLayout && id().isEmpty() )
364 {
365 //notify the model that the display name has changed
366 mLayout->itemsModel()->updateItemDisplayName( this );
367 }
368}
370{
371 return mTitle;
372}
373
374Qt::AlignmentFlag QgsLayoutItemLegend::titleAlignment() const
375{
376 return mSettings.titleAlignment();
377}
378
379void QgsLayoutItemLegend::setTitleAlignment( Qt::AlignmentFlag alignment )
380{
381 mSettings.setTitleAlignment( alignment );
382}
383
385{
386 return mSettings.rstyle( s );
387}
388
390{
391 return mSettings.style( s );
392}
393
395{
396 mSettings.setStyle( s, style );
397}
398
400{
402 return mSettings.style( s ).font();
404}
405
407{
409 rstyle( s ).setFont( f );
411}
412
414{
415 rstyle( s ).setMargin( margin );
416}
417
419{
420 rstyle( s ).setMargin( side, margin );
421}
422
424{
426 return mSettings.lineSpacing();
428}
429
431{
433 mSettings.setLineSpacing( spacing );
435}
436
438{
439 return mSettings.boxSpace();
440}
441
443{
444 mSettings.setBoxSpace( s );
445}
446
448{
449 return mSettings.columnSpace();
450}
451
453{
454 mSettings.setColumnSpace( s );
455}
456
458{
460 return mSettings.fontColor();
462}
463
465{
467 mSettings.setFontColor( c );
469}
470
472{
473 return mSettings.symbolSize().width();
474}
475
477{
478 mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
479}
480
482{
483 return mSettings.maximumSymbolSize();
484}
485
487{
488 mSettings.setMaximumSymbolSize( size );
489}
490
492{
493 return mSettings.minimumSymbolSize();
494}
495
497{
498 mSettings.setMinimumSymbolSize( size );
499}
500
501void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
502{
503 mSettings.setSymbolAlignment( alignment );
504}
505
507{
508 return mSettings.symbolAlignment();
509}
510
512{
513 return mSettings.symbolSize().height();
514}
515
517{
518 mSettings.setSymbolSize( QSizeF( mSettings.symbolSize().width(), h ) );
519}
520
522{
523 return mSettings.wmsLegendSize().width();
524}
525
527{
528 mSettings.setWmsLegendSize( QSizeF( w, mSettings.wmsLegendSize().height() ) );
529}
530
532{
533 return mSettings.wmsLegendSize().height();
534}
536{
537 mSettings.setWmsLegendSize( QSizeF( mSettings.wmsLegendSize().width(), h ) );
538}
539
541{
542 mSettings.setWrapChar( t );
543}
544
546{
547 return mSettings.wrapChar();
548}
549
551{
552 return mColumnCount;
553}
554
556{
557 mColumnCount = c;
558 mSettings.setColumnCount( c );
559}
560
562{
563 return mSettings.splitLayer();
564}
565
567{
568 mSettings.setSplitLayer( s );
569}
570
572{
573 return mSettings.equalColumnWidth();
574}
575
577{
578 mSettings.setEqualColumnWidth( s );
579}
580
582{
583 return mSettings.drawRasterStroke();
584}
585
587{
588 mSettings.setDrawRasterStroke( enabled );
589}
590
592{
593 return mSettings.rasterStrokeColor();
594}
595
597{
598 mSettings.setRasterStrokeColor( color );
599}
600
602{
603 return mSettings.rasterStrokeWidth();
604}
605
607{
608 mSettings.setRasterStrokeWidth( width );
609}
610
612{
614 updateFilterByMap( false );
615}
616
617bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
618{
619
620 //write general properties
621 legendElem.setAttribute( QStringLiteral( "title" ), mTitle );
622 legendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
623 legendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
624 legendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
625 legendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
626
627 legendElem.setAttribute( QStringLiteral( "boxSpace" ), QString::number( mSettings.boxSpace() ) );
628 legendElem.setAttribute( QStringLiteral( "columnSpace" ), QString::number( mSettings.columnSpace() ) );
629
630 legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
631 legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
632 legendElem.setAttribute( QStringLiteral( "maxSymbolSize" ), QString::number( mSettings.maximumSymbolSize() ) );
633 legendElem.setAttribute( QStringLiteral( "minSymbolSize" ), QString::number( mSettings.minimumSymbolSize() ) );
634
635 legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
636
637 legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
638
639 legendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterStroke() );
640 legendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterStrokeColor() ) );
641 legendElem.setAttribute( QStringLiteral( "rasterBorderWidth" ), QString::number( mSettings.rasterStrokeWidth() ) );
642
643 legendElem.setAttribute( QStringLiteral( "wmsLegendWidth" ), QString::number( mSettings.wmsLegendSize().width() ) );
644 legendElem.setAttribute( QStringLiteral( "wmsLegendHeight" ), QString::number( mSettings.wmsLegendSize().height() ) );
645 legendElem.setAttribute( QStringLiteral( "wrapChar" ), mSettings.wrapChar() );
646
647 legendElem.setAttribute( QStringLiteral( "resizeToContents" ), mSizeToContents );
648
649 if ( mMap )
650 {
651 legendElem.setAttribute( QStringLiteral( "map_uuid" ), mMap->uuid() );
652 }
653
654 if ( !mFilterByMapItems.empty() )
655 {
656 QDomElement filterByMapsElem = doc.createElement( QStringLiteral( "filterByMaps" ) );
657 for ( QgsLayoutItemMap *map : mFilterByMapItems )
658 {
659 if ( map )
660 {
661 QDomElement mapElem = doc.createElement( QStringLiteral( "map" ) );
662 mapElem.setAttribute( QStringLiteral( "uuid" ), map->uuid() );
663 filterByMapsElem.appendChild( mapElem );
664 }
665 }
666 legendElem.appendChild( filterByMapsElem );
667 }
668
669 QDomElement legendStyles = doc.createElement( QStringLiteral( "styles" ) );
670 legendElem.appendChild( legendStyles );
671
672 style( QgsLegendStyle::Title ).writeXml( QStringLiteral( "title" ), legendStyles, doc, context );
673 style( QgsLegendStyle::Group ).writeXml( QStringLiteral( "group" ), legendStyles, doc, context );
674 style( QgsLegendStyle::Subgroup ).writeXml( QStringLiteral( "subgroup" ), legendStyles, doc, context );
675 style( QgsLegendStyle::Symbol ).writeXml( QStringLiteral( "symbol" ), legendStyles, doc, context );
676 style( QgsLegendStyle::SymbolLabel ).writeXml( QStringLiteral( "symbolLabel" ), legendStyles, doc, context );
677
678 if ( mCustomLayerTree )
679 {
680 // if not using auto-update - store the custom layer tree
681 mCustomLayerTree->writeXml( legendElem, context );
682 }
683
684 if ( mLegendFilterByMap )
685 {
686 legendElem.setAttribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "1" ) );
687 }
688 legendElem.setAttribute( QStringLiteral( "legendFilterByAtlas" ), mFilterOutAtlas ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
689
690 return true;
691}
692
693bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
694{
695 //read general properties
696 mTitle = itemElem.attribute( QStringLiteral( "title" ) );
697 mSettings.setTitle( mTitle );
698 if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
699 {
700 mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
701 }
702 int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
703 if ( colCount < 1 ) colCount = 1;
704 mColumnCount = colCount;
705 mSettings.setColumnCount( mColumnCount );
706 mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
707 mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
708
709 const QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
710 if ( !stylesNodeList.isEmpty() )
711 {
712 const QDomNode stylesNode = stylesNodeList.at( 0 );
713 for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
714 {
715 const QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
717 style.readXml( styleElem, doc, context );
718 const QString name = styleElem.attribute( QStringLiteral( "name" ) );
720 if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
721 else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
722 else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
723 else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
724 else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
725 else continue;
726 setStyle( s, style );
727 }
728 }
729
730 //font color
731 if ( itemElem.hasAttribute( QStringLiteral( "fontColor" ) ) )
732 {
733 QColor fontClr;
734 fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
739 }
740
741 //spaces
742 mSettings.setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
743 mSettings.setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
744
745 mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
746 mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );
747
748 mSettings.setMaximumSymbolSize( itemElem.attribute( QStringLiteral( "maxSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
749 mSettings.setMinimumSymbolSize( itemElem.attribute( QStringLiteral( "minSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
750
751 mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
752
753 if ( itemElem.hasAttribute( QStringLiteral( "lineSpacing" ) ) )
754 {
755 const double spacing = itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble();
756 // line spacing *was* a fixed amount (in mm) added between each line of text.
758 // assume font sizes in points, since that was what we always had from before this method was deprecated
759 f.setLineHeight( f.size() * 0.352778 + spacing );
760 f.setLineHeightUnit( Qgis::RenderUnit::Millimeters );
762
764 f.setLineHeight( f.size() * 0.352778 + spacing );
765 f.setLineHeightUnit( Qgis::RenderUnit::Millimeters );
767
769 f.setLineHeight( f.size() * 0.352778 + spacing );
770 f.setLineHeightUnit( Qgis::RenderUnit::Millimeters );
772
774 f.setLineHeight( f.size() * 0.352778 + spacing );
775 f.setLineHeightUnit( Qgis::RenderUnit::Millimeters );
777 }
778
779 mSettings.setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
780 mSettings.setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
781 mSettings.setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
782
783 mSettings.setWrapChar( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
784
785 mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
786
787 // map
788 mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
789
790 mMapUuid.clear();
791 if ( !itemElem.attribute( QStringLiteral( "map_uuid" ) ).isEmpty() )
792 {
793 mMapUuid = itemElem.attribute( QStringLiteral( "map_uuid" ) );
794 }
795
796 mFilterByMapUuids.clear();
797 {
798 const QDomElement filterByMapsElem = itemElem.firstChildElement( QStringLiteral( "filterByMaps" ) );
799 if ( !filterByMapsElem.isNull() )
800 {
801 QDomElement mapsElem = filterByMapsElem.firstChildElement( QStringLiteral( "map" ) );
802 while ( !mapsElem.isNull() )
803 {
804 mFilterByMapUuids << mapsElem.attribute( QStringLiteral( "uuid" ) );
805 mapsElem = mapsElem.nextSiblingElement( QStringLiteral( "map" ) );
806 }
807 }
808 else if ( !mMapUuid.isEmpty() )
809 {
810 // for compatibility with < QGIS 3.32 projects
811 mFilterByMapUuids << mMapUuid;
812 }
813 }
814
815 // disconnect current map
816 setupMapConnections( mMap, false );
817 mMap = nullptr;
818
819 mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
820
821 // QGIS >= 2.6
822 QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
823 if ( layerTreeElem.isNull() )
824 layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
825
826 if ( !layerTreeElem.isNull() )
827 {
828 std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
829 if ( mLayout )
830 tree->resolveReferences( mLayout->project(), true );
831 setCustomLayerTree( tree.release() );
832 }
833 else
834 setCustomLayerTree( nullptr );
835
836 return true;
837}
838
840{
841 if ( !id().isEmpty() )
842 {
843 return id();
844 }
845
846 //if no id, default to portion of title text
847 QString text = mSettings.title();
848 if ( text.isEmpty() )
849 {
850 return tr( "<Legend>" );
851 }
852 if ( text.length() > 25 )
853 {
854 return tr( "%1…" ).arg( text.left( 25 ) );
855 }
856 else
857 {
858 return text;
859 }
860}
861
862
863void QgsLayoutItemLegend::setupMapConnections( QgsLayoutItemMap *map, bool connectSlots )
864{
865 if ( !map )
866 return;
867
868 if ( !connectSlots )
869 {
870 disconnect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
871 disconnect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
872 disconnect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
873 disconnect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
874 disconnect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
875 disconnect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
876 }
877 else
878 {
879 connect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
880 connect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
881 connect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
882 connect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
883 connect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
884 connect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
885 }
886}
887
889{
890 if ( mMap == map )
891 return;
892
893 if ( mMap )
894 {
895 setupMapConnections( mMap, false );
896 }
897
898 mMap = map;
899
900 if ( mMap )
901 {
902 setupMapConnections( mMap, true );
903 mapThemeChanged( mMap->themeToRender( mMap->createExpressionContext() ) );
904 }
905
907}
908
909void QgsLayoutItemLegend::setFilterByMapItems( const QList<QgsLayoutItemMap *> &maps )
910{
911 if ( filterByMapItems() == maps )
912 return;
913
914 for ( QgsLayoutItemMap *map : std::as_const( mFilterByMapItems ) )
915 {
916 setupMapConnections( map, false );
917 }
918
919 mFilterByMapItems.clear();
920 mFilterByMapItems.reserve( maps.size() );
921 for ( QgsLayoutItemMap *map : maps )
922 {
923 if ( map )
924 {
925 mFilterByMapItems.append( map );
926 setupMapConnections( map, true );
927 }
928 }
929
931}
932
933QList<QgsLayoutItemMap *> QgsLayoutItemLegend::filterByMapItems() const
934{
935 QList<QgsLayoutItemMap *> res;
936 res.reserve( mFilterByMapItems.size() );
937 for ( QgsLayoutItemMap *map : mFilterByMapItems )
938 {
939 if ( map )
940 res.append( map );
941 }
942 return res;
943}
944
945void QgsLayoutItemLegend::invalidateCurrentMap()
946{
947 setLinkedMap( nullptr );
948}
949
951{
953
954 bool forceUpdate = false;
955 //updates data defined properties and redraws item to match
956 if ( property == QgsLayoutObject::LegendTitle || property == QgsLayoutObject::AllProperties )
957 {
958 bool ok = false;
959 const QString t = mDataDefinedProperties.valueAsString( QgsLayoutObject::LegendTitle, context, mTitle, &ok );
960 if ( ok )
961 {
962 mSettings.setTitle( t );
963 forceUpdate = true;
964 }
965 }
967 {
968 bool ok = false;
969 const int cols = mDataDefinedProperties.valueAsInt( QgsLayoutObject::LegendColumnCount, context, mColumnCount, &ok );
970 if ( ok && cols >= 0 )
971 {
972 mSettings.setColumnCount( cols );
973 forceUpdate = true;
974 }
975 }
976 if ( forceUpdate )
977 {
979 update();
980 }
981
983}
984
985
986void QgsLayoutItemLegend::updateFilterByMapAndRedraw()
987{
988 updateFilterByMap( true );
989}
990
991void QgsLayoutItemLegend::setModelStyleOverrides( const QMap<QString, QString> &overrides )
992{
993 mLegendModel->setLayerStyleOverrides( overrides );
994 const QList< QgsLayerTreeLayer * > layers = mLegendModel->rootGroup()->findLayers();
995 for ( QgsLayerTreeLayer *nodeLayer : layers )
996 mLegendModel->refreshLayerLegend( nodeLayer );
997
998}
999
1000void QgsLayoutItemLegend::clearLegendCachedData()
1001{
1002 std::function< void( QgsLayerTreeNode * ) > clearNodeCache;
1003 clearNodeCache = [&]( QgsLayerTreeNode * node )
1004 {
1005 mLegendModel->clearCachedData( node );
1006 if ( QgsLayerTree::isGroup( node ) )
1007 {
1009 const QList< QgsLayerTreeNode * > children = group->children();
1010 for ( QgsLayerTreeNode *child : children )
1011 {
1012 clearNodeCache( child );
1013 }
1014 }
1015 };
1016
1017 clearNodeCache( mLegendModel->rootGroup() );
1018}
1019
1020void QgsLayoutItemLegend::mapLayerStyleOverridesChanged()
1021{
1022 if ( !mMap )
1023 return;
1024
1025 // map's style has been changed, so make sure to update the legend here
1026 if ( mLegendFilterByMap )
1027 {
1028 // legend is being filtered by map, so we need to re run the hit test too
1029 // as the style overrides may also have affected the visible symbols
1030 updateFilterByMap( false );
1031 }
1032 else
1033 {
1034 setModelStyleOverrides( mMap->layerStyleOverrides() );
1035 }
1036
1037 adjustBoxSize();
1038
1039 updateFilterByMap( false );
1040}
1041
1042void QgsLayoutItemLegend::mapThemeChanged( const QString &theme )
1043{
1044 if ( mThemeName == theme )
1045 return;
1046
1047 mThemeName = theme;
1048
1049 // map's theme has been changed, so make sure to update the legend here
1050 if ( mLegendFilterByMap )
1051 {
1052 // legend is being filtered by map, so we need to re run the hit test too
1053 // as the style overrides may also have affected the visible symbols
1054 updateFilterByMap( false );
1055 }
1056 else
1057 {
1058 if ( mThemeName.isEmpty() )
1059 {
1060 setModelStyleOverrides( QMap<QString, QString>() );
1061 }
1062 else
1063 {
1064 // get style overrides for theme
1065 const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
1066 setModelStyleOverrides( overrides );
1067 }
1068 }
1069
1070 adjustBoxSize();
1071
1073}
1074
1076{
1077 // ask for update
1078 // the actual update will take place before the redraw.
1079 // This is to avoid multiple calls to the filter
1080 mFilterAskedForUpdate = true;
1081
1082 if ( redraw )
1083 update();
1084}
1085
1086void QgsLayoutItemLegend::doUpdateFilterByMap()
1087{
1088 if ( mMap )
1089 {
1090 if ( !mThemeName.isEmpty() )
1091 {
1092 // get style overrides for theme
1093 const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
1094 mLegendModel->setLayerStyleOverrides( overrides );
1095 }
1096 else
1097 {
1098 mLegendModel->setLayerStyleOverrides( mMap->layerStyleOverrides() );
1099 }
1100 }
1101 else
1102 mLegendModel->setLayerStyleOverrides( QMap<QString, QString>() );
1103
1104
1105 const bool filterByExpression = QgsLayerTreeUtils::hasLegendFilterExpression( *( mCustomLayerTree ? mCustomLayerTree.get() : mLayout->project()->layerTreeRoot() ) );
1106
1107 const bool hasValidFilter = filterByExpression
1108 || ( mLegendFilterByMap && ( mMap || !mFilterByMapItems.empty() ) )
1109 || mInAtlas;
1110
1111 if ( hasValidFilter )
1112 {
1113 const double dpi = mLayout->renderContext().dpi();
1114
1115 QSet< QgsLayoutItemMap * > linkedFilterMaps;
1116 if ( mLegendFilterByMap )
1117 {
1118 linkedFilterMaps = qgis::listToSet( filterByMapItems() );
1119 if ( mMap )
1120 linkedFilterMaps.insert( mMap );
1121 }
1122
1123 QgsMapSettings mapSettings;
1124 QgsGeometry filterGeometry;
1125 if ( mMap )
1126 {
1127 // if a specific linked map has been set, use it for the reference scale and extent
1128 const QgsRectangle requestRectangle = mMap->requestedExtent();
1129 QSizeF size( requestRectangle.width(), requestRectangle.height() );
1130 size *= mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), Qgis::LayoutUnit::Millimeters ).length() * dpi / 25.4;
1131 mapSettings = mMap->mapSettings( requestRectangle, size, dpi, true );
1132
1133 filterGeometry = QgsGeometry::fromQPolygonF( mMap->visibleExtentPolygon() );
1134 }
1135 else if ( !linkedFilterMaps.empty() )
1136 {
1137 // otherwise just take the first linked filter map
1138 const QgsRectangle requestRectangle = ( *linkedFilterMaps.constBegin() )->requestedExtent();
1139 QSizeF size( requestRectangle.width(), requestRectangle.height() );
1140 size *= mLayout->convertFromLayoutUnits( ( *linkedFilterMaps.constBegin() )->mapUnitsToLayoutUnits(), Qgis::LayoutUnit::Millimeters ).length() * dpi / 25.4;
1141 mapSettings = ( *linkedFilterMaps.constBegin() )->mapSettings( requestRectangle, size, dpi, true );
1142
1143 filterGeometry = QgsGeometry::fromQPolygonF( ( *linkedFilterMaps.constBegin() )->visibleExtentPolygon() );
1144 }
1145
1147
1148 const QgsGeometry atlasGeometry = mInAtlas ? mLayout->reportContext().currentGeometry( mapSettings.destinationCrs() ) : QgsGeometry();
1149
1150 QgsLayerTreeFilterSettings filterSettings( mapSettings );
1151
1152 if ( !linkedFilterMaps.empty() )
1153 {
1154 for ( QgsLayoutItemMap *map : std::as_const( linkedFilterMaps ) )
1155 {
1156 if ( map == mMap )
1157 continue;
1158
1160
1161 //transform back to destination CRS
1162 const QgsCoordinateTransform mapTransform( map->crs(), mapSettings.destinationCrs(), mLayout->project() );
1163 try
1164 {
1165 mapExtent.transform( mapTransform );
1166 }
1167 catch ( QgsCsException &cse )
1168 {
1169 continue;
1170 }
1171
1172 const QList< QgsMapLayer * > layersForMap = map->layersToRender();
1173 for ( QgsMapLayer *layer : layersForMap )
1174 {
1175 if ( !atlasGeometry.isNull() )
1176 {
1177 mapExtent = mapExtent.intersection( atlasGeometry );
1178 }
1179
1180 filterSettings.addVisibleExtentForLayer( layer, QgsReferencedGeometry( mapExtent, mapSettings.destinationCrs() ) );
1181 }
1182 }
1183 }
1184
1185 if ( mInAtlas )
1186 {
1187 if ( !filterGeometry.isEmpty() )
1188 filterGeometry = mLayout->reportContext().currentGeometry( mapSettings.destinationCrs() );
1189 else
1190 filterGeometry = filterGeometry.intersection( mLayout->reportContext().currentGeometry( mapSettings.destinationCrs() ) );
1191 }
1192
1193 filterSettings.setLayerFilterExpressionsFromLayerTree( mLegendModel->rootGroup() );
1194 if ( !filterGeometry.isNull() )
1195 {
1196 filterSettings.setFilterPolygon( filterGeometry );
1197 }
1198 else
1199 {
1200 filterSettings.setFlags( Qgis::LayerTreeFilterFlag::SkipVisibilityCheck );
1201 }
1202
1203 mLegendModel->setFilterSettings( &filterSettings );
1204 }
1205 else
1206 {
1207 mLegendModel->setFilterSettings( nullptr );
1208 }
1209
1210 clearLegendCachedData();
1211 mForceResize = true;
1212}
1213
1215{
1216 return mThemeName;
1217}
1218
1220{
1221 mFilterOutAtlas = doFilter;
1222}
1223
1225{
1226 return mFilterOutAtlas;
1227}
1228
1229void QgsLayoutItemLegend::onAtlasFeature()
1230{
1231 if ( !mLayout || !mLayout->reportContext().feature().isValid() )
1232 return;
1233 mInAtlas = mFilterOutAtlas;
1235}
1236
1237void QgsLayoutItemLegend::onAtlasEnded()
1238{
1239 mInAtlas = false;
1241}
1242
1244{
1246
1247 // We only want the last scope from the map's expression context, as this contains
1248 // the map specific variables. We don't want the rest of the map's context, because that
1249 // will contain duplicate global, project, layout, etc scopes.
1250 if ( mMap )
1251 context.appendScope( mMap->createExpressionContext().popScope() );
1252
1253 QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Legend Settings" ) );
1254
1255 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_title" ), title(), true ) );
1256 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_column_count" ), columnCount(), true ) );
1257 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_split_layers" ), splitLayer(), true ) );
1258 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_wrap_string" ), wrapString(), true ) );
1259 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_by_map" ), legendFilterByMapEnabled(), true ) );
1260 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_out_atlas" ), legendFilterOutAtlas(), true ) );
1261
1262 context.appendScope( scope );
1263 return context;
1264}
1265
1267{
1268 return MustPlaceInOwnLayer;
1269}
1270
1272{
1273 std::function<bool( QgsLayerTreeGroup *group ) >visit;
1274
1275 visit = [ =, &visit]( QgsLayerTreeGroup * group ) -> bool
1276 {
1277 const QList<QgsLayerTreeNode *> childNodes = group->children();
1278 for ( QgsLayerTreeNode *node : childNodes )
1279 {
1280 if ( QgsLayerTree::isGroup( node ) )
1281 {
1282 QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
1283 if ( !visit( nodeGroup ) )
1284 return false;
1285 }
1286 else if ( QgsLayerTree::isLayer( node ) )
1287 {
1288 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
1289 if ( !nodeLayer->patchShape().isNull() )
1290 {
1291 QgsStyleLegendPatchShapeEntity entity( nodeLayer->patchShape() );
1292 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1293 return false;
1294 }
1295 const QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->layerLegendNodes( nodeLayer );
1296 for ( QgsLayerTreeModelLegendNode *legendNode : legendNodes )
1297 {
1298 if ( QgsSymbolLegendNode *symbolNode = dynamic_cast< QgsSymbolLegendNode * >( legendNode ) )
1299 {
1300 if ( !symbolNode->patchShape().isNull() )
1301 {
1302 QgsStyleLegendPatchShapeEntity entity( symbolNode->patchShape() );
1303 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1304 return false;
1305 }
1306 }
1307 }
1308 }
1309 }
1310 return true;
1311 };
1312 return visit( mLegendModel->rootGroup( ) );
1313}
1314
1316{
1317 return mLegendModel->hitTestInProgress();
1318}
1319
1320
1321// -------------------------------------------------------------------------
1322
1324 : QgsLayerTreeModel( rootNode, parent )
1325 , mLayoutLegend( layout )
1326{
1330 connect( this, &QgsLegendModel::dataChanged, this, &QgsLegendModel::refreshLegend );
1331}
1332
1334 : QgsLayerTreeModel( rootNode )
1335 , mLayoutLegend( layout )
1336{
1340 connect( this, &QgsLegendModel::dataChanged, this, &QgsLegendModel::refreshLegend );
1341}
1342
1343QVariant QgsLegendModel::data( const QModelIndex &index, int role ) const
1344{
1345 // handle custom layer node labels
1346
1348 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::isLayer( node ) ? QgsLayerTree::toLayer( node ) : nullptr;
1349 if ( nodeLayer && ( role == Qt::DisplayRole || role == Qt::EditRole ) )
1350 {
1351 QString name = node->customProperty( QStringLiteral( "cached_name" ) ).toString();
1352 if ( !name.isEmpty() )
1353 return name;
1354
1355 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
1356
1357 //finding the first label that is stored
1358 name = nodeLayer->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1359 if ( name.isEmpty() )
1360 name = nodeLayer->name();
1361 if ( name.isEmpty() )
1362 name = node->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1363 if ( name.isEmpty() )
1364 name = node->name();
1365 if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() )
1366 {
1367 if ( vlayer && vlayer->featureCount() >= 0 )
1368 {
1369 name += QStringLiteral( " [%1]" ).arg( vlayer->featureCount() );
1370 node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1371 return name;
1372 }
1373 }
1374
1375 const bool evaluate = ( vlayer && !nodeLayer->labelExpression().isEmpty() ) || name.contains( "[%" );
1376 if ( evaluate )
1377 {
1378 QgsExpressionContext expressionContext;
1379 if ( vlayer )
1380 {
1381 connect( vlayer, &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsLegendModel::forceRefresh, Qt::UniqueConnection );
1382 // counting is done here to ensure that a valid vector layer needs to be evaluated, count is used to validate previous count or update the count if invalidated
1383 vlayer->countSymbolFeatures();
1384 }
1385
1386 if ( mLayoutLegend )
1387 expressionContext = mLayoutLegend->createExpressionContext();
1388
1389 const QList<QgsLayerTreeModelLegendNode *> legendnodes = layerLegendNodes( nodeLayer, false );
1390 if ( ! legendnodes.isEmpty() )
1391 {
1392 if ( legendnodes.count() > 1 ) // evaluate all existing legend nodes but leave the name for the legend evaluator
1393 {
1394 for ( QgsLayerTreeModelLegendNode *treenode : legendnodes )
1395 {
1396 if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( treenode ) )
1397 symnode->evaluateLabel( expressionContext );
1398 }
1399 }
1400 else if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( legendnodes.first() ) )
1401 symnode->evaluateLabel( expressionContext );
1402 }
1403 }
1404 node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1405 return name;
1406 }
1407 return QgsLayerTreeModel::data( index, role );
1408}
1409
1410Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
1411{
1412 // make the legend nodes selectable even if they are not by default
1413 if ( index2legendNode( index ) )
1414 return QgsLayerTreeModel::flags( index ) | Qt::ItemIsSelectable;
1415
1417}
1418
1419QList<QgsLayerTreeModelLegendNode *> QgsLegendModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent ) const
1420{
1421 if ( !mLegend.contains( nodeLayer ) )
1422 return QList<QgsLayerTreeModelLegendNode *>();
1423
1424 const LayerLegendData &data = mLegend[nodeLayer];
1425 QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
1426 if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
1427 lst.prepend( data.embeddedNodeInParent );
1428 return lst;
1429}
1430
1432{
1433 node->removeCustomProperty( QStringLiteral( "cached_name" ) );
1434}
1435
1436void QgsLegendModel::forceRefresh()
1437{
1438 emit refreshLegend();
1439}
@ SkipVisibilityCheck
If set, the standard visibility check should be skipped.
int valueAsInt(int key, const QgsExpressionContext &context, int defaultValue=0, bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as an integer.
QString valueAsString(int key, const QgsExpressionContext &context, const QString &defaultString=QString(), bool *ok=nullptr) const
Calculates the current value of the property with the specified key and interprets it as a string.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Class for doing transforms between two map coordinate systems.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:67
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.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:164
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false) SIP_THROW(QgsCsException)
Transforms this geometry as described by the coordinate transform ct.
static QgsGeometry fromQPolygonF(const QPolygonF &polygon)
Construct geometry from a QPolygonF.
Q_GADGET bool isNull
Definition: qgsgeometry.h:166
QgsGeometry intersection(const QgsGeometry &geometry, const QgsGeometryParameters &parameters=QgsGeometryParameters()) const
Returns a geometry representing the points shared by this geometry and other.
bool isEmpty() const
Returns true if the geometry is empty (eg a linestring with no vertices, or a collection with no geom...
Contains settings relating to filtering the contents of QgsLayerTreeModel and views.
Layer tree group node serves as a container for layers and further groups.
Layer tree node points to a map layer.
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
QgsLegendPatchShape patchShape() const
Returns the symbol patch shape to use when rendering the legend node symbol.
QString name() const override
Returns the layer's name.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
The QgsLayerTreeModel class is model implementation for Qt item views framework.
Flags flags() const
Returns OR-ed combination of model flags.
void hitTestStarted()
Emitted when a hit test for visible legend items starts.
void hitTestCompleted()
Emitted when a hit test for visible legend items completes.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
QHash< QgsLayerTreeLayer *, LayerLegendData > mLegend
Per layer data about layer's legend nodes.
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given index.
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Returns legend node for given index.
@ AllowNodeReorder
Allow reordering with drag'n'drop.
@ AllowLegendChangeState
Allow check boxes for legend nodes (if supported by layer's legend)
@ UseThreadedHitTest
Run legend hit tests in a background thread (since QGIS 3.30)
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.
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
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.
virtual QString name() const =0
Returns name of the node.
void customPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Emitted when a custom property of a node within the tree has been changed or removed.
static bool hasLegendFilterExpression(const QgsLayerTreeGroup &group)
Test if one of the layers in a group has an expression filter.
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:33
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
static QgsLayerTree * readXml(QDomElement &element, const QgsReadWriteContext &context)
Load the layer tree from an XML element.
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
A layout item subclass for map legends.
bool autoUpdateModel() const
Returns whether the legend content should auto update to reflect changes in the project's layer tree.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void setStyleMargin(QgsLegendStyle::Style component, double margin)
Set the margin for a legend component.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
QString title() const
Returns the legend title.
void setSplitLayer(bool enabled)
Sets whether the legend items from a single layer can be split over multiple columns.
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
void adjustBoxSize()
Sets the legend's item bounds to fit the whole legend content.
double wmsLegendWidth() const
Returns the WMS legend width.
void setColumnSpace(double spacing)
Sets the legend column spacing.
void setBoxSpace(double space)
Sets the legend box space.
bool splitLayer() const
Returns whether the legend items from a single layer can be split over multiple columns.
double symbolHeight() const
Returns the legend symbol height.
void updateFilterByMap(bool redraw=true)
Updates the legend content when filtered by map.
void setEqualColumnWidth(bool equalize)
Sets whether column widths should be equalized.
void setDrawRasterStroke(bool enabled)
Sets whether a stroke will be drawn around raster symbol items.
Q_DECL_DEPRECATED QFont styleFont(QgsLegendStyle::Style component) const
Returns the font settings for a legend component.
static QgsLayoutItemLegend * create(QgsLayout *layout)
Returns a new legend item for the specified layout.
void setLegendFilterOutAtlas(bool doFilter)
When set to true, during an atlas rendering, it will filter out legend elements where features are ou...
void setSymbolWidth(double width)
Sets the legend symbol width.
QString wrapString() const
Returns the legend text wrapping string.
bool resizeToContents() const
Returns whether the legend should automatically resize to fit its contents.
void setResizeToContents(bool enabled)
Sets whether the legend should automatically resize to fit its contents.
void updateLegend()
Updates the model and all legend entries.
QgsLayoutItemLegend(QgsLayout *layout)
Constructor for QgsLayoutItemLegend, with the specified parent layout.
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map to associate with the legend.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
QgsLegendStyle & rstyle(QgsLegendStyle::Style s)
Returns reference to modifiable legend style.
Q_DECL_DEPRECATED QColor fontColor() const
Returns the legend font color.
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
double maximumSymbolSize() const
Returns the maximum symbol size (in mm).
void setWmsLegendWidth(double width)
Sets the WMS legend width.
void setTitle(const QString &title)
Sets the legend title.
Q_DECL_DEPRECATED void setFontColor(const QColor &color)
Sets the legend font color.
double boxSpace() const
Returns the legend box space.
void setRasterStrokeColor(const QColor &color)
Sets the stroke color for the stroke drawn around raster symbol items.
QString displayName() const override
Gets item display name.
bool isRefreshing() const override
Returns true if the item is currently refreshing content in the background.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
double symbolWidth() const
Returns the legend symbol width.
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item's contents using the specified item render context.
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
int type() const override
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
bool legendFilterOutAtlas() const
Returns whether to filter out legend elements outside of the current atlas feature.
void setStyle(QgsLegendStyle::Style component, const QgsLegendStyle &style)
Sets the style of component to style for the legend.
ExportLayerBehavior exportLayerBehavior() const override
Returns the behavior of this item during exporting to layered exports (e.g.
Q_DECL_DEPRECATED void setLineSpacing(double spacing)
Sets the spacing in-between multiple lines.
double columnSpace() const
Returns the legend column spacing.
QgsLayoutItem::Flags itemFlags() const override
Returns the item's flags, which indicate how the item behaves.
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
void setFilterByMapItems(const QList< QgsLayoutItemMap * > &maps)
Sets the maps to use when filtering legend content by map extents.
void setLegendFilterByMapEnabled(bool enabled)
Set whether legend items should be filtered to show just the ones visible in the associated map.
QList< QgsLayoutItemMap * > filterByMapItems() const
Returns the maps to use when filtering legend content by map extents.
void setSymbolHeight(double height)
Sets the legend symbol height.
void setMinimumSymbolSize(double size)
Set the minimum symbol size for symbol (in millimeters).
void setAutoUpdateModel(bool autoUpdate)
Sets whether the legend content should auto update to reflect changes in the project's layer tree.
void setMaximumSymbolSize(double size)
Set the maximum symbol size for symbol (in millimeters).
QIcon icon() const override
Returns the item's icon.
double wmsLegendHeight() const
Returns the WMS legend height.
void setWmsLegendHeight(double height)
Sets the WMS legend height.
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
double minimumSymbolSize() const
Returns the minimum symbol size (in mm).
double rasterStrokeWidth() const
Returns the stroke width (in layout units) for the stroke drawn around raster symbol items.
Q_DECL_DEPRECATED double lineSpacing() const
Returns the spacing in-between lines in layout units.
void invalidateCache() override
Q_DECL_DEPRECATED void setStyleFont(QgsLegendStyle::Style component, const QFont &font)
Sets the style font for a legend component.
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns legend style.
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
void setWrapString(const QString &string)
Sets the legend text wrapping string.
QString themeName() const
Returns the name of the theme currently linked to the legend.
void setColumnCount(int count)
Sets the legend column count.
bool equalColumnWidth() const
Returns whether column widths should be equalized.
int columnCount() const
Returns the legend column count.
bool legendFilterByMapEnabled() const
Find out whether legend items are filtered to show just the ones visible in the associated map.
Layout graphical items for displaying a map.
void extentChanged()
Emitted when the map's extent changes.
QgsMapSettings mapSettings(const QgsRectangle &extent, QSizeF size, double dpi, bool includeLayerSettings) const
Returns map settings that will be used for drawing of the map.
void layerStyleOverridesChanged()
Emitted when layer style overrides are changed... a means to let associated legend items know they sh...
void mapRotationChanged(double newRotation)
Emitted when the map's rotation changes.
QPolygonF visibleExtentPolygon() const
Returns a polygon representing the current visible map extent, considering map extents and rotation.
QgsRectangle requestedExtent() const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
QList< QgsMapLayer * > layersToRender(const QgsExpressionContext *context=nullptr) const
Returns a list of the layers which will be rendered within this map item, considering any locked laye...
QMap< QString, QString > layerStyleOverrides() const
Returns stored overrides of styles for layers.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
double mapUnitsToLayoutUnits() const
Returns the conversion factor from map units to layout units.
void themeChanged(const QString &theme)
Emitted when the map's associated theme is changed.
QgsRectangle extent() const
Returns the current map extent.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:71
Base class for graphical items within a QgsLayout.
QgsLayoutSize sizeWithUnits() const
Returns the item's current size, including units.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Handles preparing a paint surface for the layout item and painting the item's content.
virtual void redraw()
Triggers a redraw (update) of the item.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
virtual void attemptResize(const QgsLayoutSize &size, bool includesFrame=false)
Attempts to resize the item to a specified target size.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property's value and redrawing the...
@ FlagOverridesPaint
Item overrides the default layout item painting method.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
virtual QString uuid() const
Returns the item identification string.
QString id() const
Returns the item's ID name.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
@ MustPlaceInOwnLayer
Item must be placed in its own individual layer.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
QgsPropertyCollection mDataDefinedProperties
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
QPointer< QgsLayout > mLayout
DataDefinedProperty
Data defined properties for different item types.
@ LegendTitle
Legend title.
@ AllProperties
All properties for item.
@ LegendColumnCount
Legend column count.
@ FlagUseAdvancedEffects
Enable advanced effects such as blend modes.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:41
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
static QgsRenderContext createRenderContextForMap(QgsLayoutItemMap *map, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout map and painter destination.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:50
Item model implementation based on layer tree model for layout legend.
void clearCachedData(QgsLayerTreeNode *node) const
Clears any previously cached data for the specified node.
void refreshLegend()
Emitted to refresh the legend.
QgsLegendModel(QgsLayerTree *rootNode, QObject *parent=nullptr, QgsLayoutItemLegend *layout=nullptr)
Construct the model based on the given layer tree.
QVariant data(const QModelIndex &index, int role) const override
QList< QgsLayerTreeModelLegendNode * > layerLegendNodes(QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent=false) const
Returns filtered list of active legend nodes attached to a particular layer node (by default it retur...
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
The QgsLegendRenderer class handles automatic layout and rendering of legend.
QSizeF minimumSize(QgsRenderContext *renderContext=nullptr)
Runs the layout algorithm and returns the minimum size required for the legend.
void setLegendSize(QSizeF s)
Sets the preferred resulting legend size.
Q_DECL_DEPRECATED void drawLegend(QPainter *painter)
Draws the legend with given painter.
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
QString wrapChar() const
Returns the string used as a wrapping character.
Q_DECL_DEPRECATED void setFontColor(const QColor &c)
Sets the font color used for legend items.
void setWrapChar(const QString &t)
Sets a string to use as a wrapping character.
void setRasterStrokeColor(const QColor &color)
Sets the stroke color for the stroke drawn around raster symbol items.
void setStyle(QgsLegendStyle::Style s, const QgsLegendStyle &style)
Sets the style for a legend component.
void setColumnSpace(double s)
Sets the margin space between adjacent columns (in millimeters).
Q_DECL_DEPRECATED void setMapScale(double scale)
Sets the legend map scale.
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns the style for a legend component.
void setTitle(const QString &t)
Sets the title for the legend, which will be rendered above all legend items.
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
void setDrawRasterStroke(bool enabled)
Sets whether a stroke will be drawn around raster symbol items.
QSizeF wmsLegendSize() const
Returns the size (in millimeters) of WMS legend graphics shown in the legend.
double minimumSymbolSize() const
Returns the minimum symbol size (in mm).
double rasterStrokeWidth() const
Returns the stroke width (in millimeters) for the stroke drawn around raster symbol items.
Q_DECL_DEPRECATED void setLineSpacing(double s)
Sets the line spacing to use between lines of legend text.
void setColumnCount(int c)
Sets the desired minimum number of columns to show in the legend.
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
Q_DECL_DEPRECATED void setMmPerMapUnit(double mmPerMapUnit)
Q_DECL_DEPRECATED void setDpi(int dpi)
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
QSizeF symbolSize() const
Returns the default symbol size (in millimeters) used for legend items.
Q_DECL_DEPRECATED QColor fontColor() const
Returns the font color used for legend items.
double maximumSymbolSize() const
Returns the maximum symbol size (in mm).
QString title() const
Returns the title for the legend, which will be rendered above all legend items.
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
Q_DECL_DEPRECATED double lineSpacing() const
Returns the line spacing to use between lines of legend text.
Q_DECL_DEPRECATED void setUseAdvancedEffects(bool use)
void setSplitLayer(bool s)
Sets whether layer components can be split over multiple columns.
double columnSpace() const
Returns the margin space between adjacent columns (in millimeters).
QgsLegendStyle & rstyle(QgsLegendStyle::Style s)
Returns modifiable reference to the style for a legend component.
void setEqualColumnWidth(bool s)
Sets whether all columns should have equal widths.
void setBoxSpace(double s)
Sets the legend box space (in millimeters), which is the empty margin around the inside of the legend...
double boxSpace() const
Returns the legend box space (in millimeters), which is the empty margin around the inside of the leg...
void setMaximumSymbolSize(double size)
Set the maximum symbol size for symbol (in millimeters).
bool splitLayer() const
Returns true if layer components can be split over multiple columns.
void setMinimumSymbolSize(double size)
Set the minimum symbol size for symbol (in millimeters).
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
bool equalColumnWidth() const
Returns true if all columns should have equal widths.
void setSymbolSize(QSizeF s)
Sets the default symbol size (in millimeters) used for legend items.
void setWmsLegendSize(QSizeF s)
Sets the desired size (in millimeters) of WMS legend graphics shown in the legend.
Contains detailed styling information relating to how a layout legend should be rendered.
Q_DECL_DEPRECATED QFont font() const
Returns the font used for rendering this legend component.
QgsTextFormat & textFormat()
Returns the text format used for rendering this legend component.
void setMargin(Side side, double margin)
Sets the margin (in mm) for the specified side of the component.
Side
Margin sides.
void readXml(const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads the component's style definition from an XML element.
Style
Component of legends which can be styled.
@ Group
Legend group title.
@ Symbol
Symbol icon (excluding label)
@ Subgroup
Legend subgroup title.
@ Title
Legend title.
@ SymbolLabel
Symbol label (excluding icon)
Q_DECL_DEPRECATED void setFont(const QFont &font)
Sets the font used for rendering this legend component.
void writeXml(const QString &name, QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes the component's style definition to an XML element.
void setTextFormat(const QgsTextFormat &format)
Sets the text format used for rendering this legend component.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
The QgsMapSettings class contains configuration for rendering of the map.
double scale() const
Returns the calculated map scale.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:230
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:223
A QgsGeometry with associated coordinate reference system.
Contains information about the context of a rendering operation.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
Scoped object for saving and restoring a QPainter object's state.
An interface for classes which can visit style entity (e.g.
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
A legend patch shape entity for QgsStyle databases.
Definition: qgsstyle.h:1464
static QColor decodeColor(const QString &str)
static QString encodeColor(const QColor &color)
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
Container for all settings relating to text rendering.
Definition: qgstextformat.h:42
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setLineHeightUnit(Qgis::RenderUnit unit)
Sets the unit for the line height for text.
double size() const
Returns the size for rendered text.
void setLineHeight(double height)
Sets the line height for text.
Represents a vector layer which manages a vector based data sets.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
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
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:4572
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:4571
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
Single variable definition for use within a QgsExpressionContextScope.
Structure that stores all data associated with one map layer.
Contains information relating to the style entity currently being visited.