QGIS API Documentation 3.29.0-Master (006c3c0232)
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"
37
38#include <QDomDocument>
39#include <QDomElement>
40#include <QPainter>
42
44 : QgsLayoutItem( layout )
45 , mLegendModel( new QgsLegendModel( layout->project()->layerTreeRoot(), this ) )
46{
47#if 0 //no longer required?
48 connect( &layout->atlasComposition(), &QgsAtlasComposition::renderEnded, this, &QgsLayoutItemLegend::onAtlasEnded );
49#endif
50
51 mTitle = mSettings.title();
52
53 // Connect to the main layertreeroot.
54 // It serves in "auto update mode" as a medium between the main app legend and this one
55 connect( mLayout->project()->layerTreeRoot(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayoutItemLegend::nodeCustomPropertyChanged );
56
57 // If project colors change, we need to redraw legend, as legend symbols may rely on project colors
58 connect( mLayout->project(), &QgsProject::projectColorsChanged, this, [ = ]
59 {
60 invalidateCache();
61 update();
62 } );
63 connect( mLegendModel.get(), &QgsLegendModel::refreshLegend, this, [ = ]
64 {
65 // NOTE -- we do NOT connect to ::refresh here, as we don't want to trigger the call to onAtlasFeature() which sets mFilterAskedForUpdate to true,
66 // causing an endless loop.
67
68 // TODO -- the call to QgsLayoutItem::refresh() is probably NOT required!
69 QgsLayoutItem::refresh();
70
71 // (this one is definitely required)
72 clearLegendCachedData();
73 } );
74}
75
77{
78 return new QgsLayoutItemLegend( layout );
79}
80
82{
84}
85
87{
88 return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemLegend.svg" ) );
89}
90
91QgsLayoutItem::Flags QgsLayoutItemLegend::itemFlags() const
92{
94}
95
96void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
97{
98 if ( !painter )
99 return;
100
101 if ( mFilterAskedForUpdate )
102 {
103 mFilterAskedForUpdate = false;
104 doUpdateFilterByMap();
105 }
106
107 const int dpi = painter->device()->logicalDpiX();
108 const double dotsPerMM = dpi / 25.4;
109
110 if ( mLayout )
111 {
113 // no longer required, but left set for api stability
115 mSettings.setDpi( dpi );
117 }
118 if ( mMap && mLayout )
119 {
121 // no longer required, but left set for api stability
122 mSettings.setMmPerMapUnit( mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() );
124
125 // use a temporary QgsMapSettings to find out real map scale
126 const QSizeF mapSizePixels = QSizeF( mMap->rect().width() * dotsPerMM, mMap->rect().height() * dotsPerMM );
127 const QgsRectangle mapExtent = mMap->extent();
128
129 const QgsMapSettings ms = mMap->mapSettings( mapExtent, mapSizePixels, dpi, false );
130
131 // no longer required, but left set for api stability
133 mSettings.setMapScale( ms.scale() );
135 }
136 mInitialMapScaleCalculated = true;
137
138 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
139 legendRenderer.setLegendSize( mForceResize && mSizeToContents ? QSize() : rect().size() );
140
141 const QPointF oldPos = pos();
142
143 //adjust box if width or height is too small
144 if ( mSizeToContents )
145 {
146 QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter )
148
149 const QSizeF size = legendRenderer.minimumSize( &context );
150 if ( mForceResize )
151 {
152 mForceResize = false;
153
154 //set new rect, respecting position mode and data defined size/position
155 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
156 attemptResize( newSize );
157 }
158 else if ( size.height() > rect().height() || size.width() > rect().width() )
159 {
160 //need to resize box
161 QSizeF targetSize = rect().size();
162 if ( size.height() > targetSize.height() )
163 targetSize.setHeight( size.height() );
164 if ( size.width() > targetSize.width() )
165 targetSize.setWidth( size.width() );
166
167 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( targetSize, sizeWithUnits().units() );
168 //set new rect, respecting position mode and data defined size/position
169 attemptResize( newSize );
170 }
171 }
172
173 // attemptResize may change the legend position and would call setPos
174 // BUT the position is actually changed for the next draw, so we need to translate of the difference
175 // between oldPos and newPos
176 // the issue doesn't appear in desktop rendering but only in export because in the first one,
177 // Qt triggers a redraw on position change
178 painter->save();
179 painter->translate( pos() - oldPos );
180 QgsLayoutItem::paint( painter, itemStyle, pWidget );
181 painter->restore();
182}
183
185{
186 if ( !mMapUuid.isEmpty() )
187 {
188 setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) ) );
189 }
190}
191
193{
195 clearLegendCachedData();
196 onAtlasFeature();
197}
198
200{
201 QPainter *painter = context.renderContext().painter();
202
203 QgsRenderContext rc = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter, context.renderContext().scaleFactor() * 25.4 )
205
207
208 const QgsScopedQPainterState painterState( painter );
209
210 // painter is scaled to dots, so scale back to layout units
211 painter->scale( rc.scaleFactor(), rc.scaleFactor() );
212
213 painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
214
215 if ( !mSizeToContents )
216 {
217 // set a clip region to crop out parts of legend which don't fit
218 const QRectF thisPaintRect = QRectF( 0, 0, rect().width(), rect().height() );
219 painter->setClipRect( thisPaintRect );
220 }
221
222 if ( mLayout )
223 {
224 // no longer required, but left for API compatibility
226 mSettings.setDpi( mLayout->renderContext().dpi() );
228 }
229
230
231
232
233 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
234 legendRenderer.setLegendSize( rect().size() );
235
236 legendRenderer.drawLegend( rc );
237}
238
240{
241 if ( !mSizeToContents )
242 return;
243
244 if ( !mInitialMapScaleCalculated )
245 {
246 // this is messy - but until we have painted the item we have no knowledge of the current DPI
247 // and so cannot correctly calculate the map scale. This results in incorrect size calculations
248 // for marker symbols with size in map units, causing the legends to initially expand to huge
249 // sizes if we attempt to calculate the box size first.
250 return;
251 }
252
253 QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, nullptr ) :
255
256 QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
257 const QSizeF size = legendRenderer.minimumSize( &context );
258 QgsDebugMsgLevel( QStringLiteral( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ), 2 );
259 if ( size.isValid() )
260 {
261 const QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
262 //set new rect, respecting position mode and data defined size/position
263 attemptResize( newSize );
264 }
265}
266
268{
269 mSizeToContents = enabled;
270}
271
273{
274 return mSizeToContents;
275}
276
277void QgsLayoutItemLegend::setCustomLayerTree( QgsLayerTree *rootGroup )
278{
279 mLegendModel->setRootGroup( rootGroup ? rootGroup : ( mLayout ? mLayout->project()->layerTreeRoot() : nullptr ) );
280
281 mCustomLayerTree.reset( rootGroup );
282}
283
284
286{
287 if ( autoUpdate == autoUpdateModel() )
288 return;
289
290 setCustomLayerTree( autoUpdate ? nullptr : mLayout->project()->layerTreeRoot()->clone() );
292 updateFilterByMap( false );
293}
294
295void QgsLayoutItemLegend::nodeCustomPropertyChanged( QgsLayerTreeNode *, const QString &key )
296{
297 if ( key == QLatin1String( "cached_name" ) )
298 return;
299
300 if ( autoUpdateModel() )
301 {
302 // in "auto update" mode, some parameters on the main app legend may have been changed (expression filtering)
303 // we must then call updateItem to reflect the changes
304 updateFilterByMap( false );
305 }
306}
307
309{
310 return !mCustomLayerTree;
311}
312
314{
315 mLegendFilterByMap = enabled;
316 updateFilterByMap( false );
317}
318
319void QgsLayoutItemLegend::setTitle( const QString &t )
320{
321 mTitle = t;
322 mSettings.setTitle( t );
323
324 if ( mLayout && id().isEmpty() )
325 {
326 //notify the model that the display name has changed
327 mLayout->itemsModel()->updateItemDisplayName( this );
328 }
329}
331{
332 return mTitle;
333}
334
335Qt::AlignmentFlag QgsLayoutItemLegend::titleAlignment() const
336{
337 return mSettings.titleAlignment();
338}
339
340void QgsLayoutItemLegend::setTitleAlignment( Qt::AlignmentFlag alignment )
341{
342 mSettings.setTitleAlignment( alignment );
343}
344
346{
347 return mSettings.rstyle( s );
348}
349
351{
352 return mSettings.style( s );
353}
354
356{
357 mSettings.setStyle( s, style );
358}
359
361{
363 return mSettings.style( s ).font();
365}
366
368{
370 rstyle( s ).setFont( f );
372}
373
375{
376 rstyle( s ).setMargin( margin );
377}
378
380{
381 rstyle( s ).setMargin( side, margin );
382}
383
385{
387 return mSettings.lineSpacing();
389}
390
392{
394 mSettings.setLineSpacing( spacing );
396}
397
399{
400 return mSettings.boxSpace();
401}
402
404{
405 mSettings.setBoxSpace( s );
406}
407
409{
410 return mSettings.columnSpace();
411}
412
414{
415 mSettings.setColumnSpace( s );
416}
417
419{
421 return mSettings.fontColor();
423}
424
426{
428 mSettings.setFontColor( c );
430}
431
433{
434 return mSettings.symbolSize().width();
435}
436
438{
439 mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
440}
441
443{
444 return mSettings.maximumSymbolSize();
445}
446
448{
449 mSettings.setMaximumSymbolSize( size );
450}
451
453{
454 return mSettings.minimumSymbolSize();
455}
456
458{
459 mSettings.setMinimumSymbolSize( size );
460}
461
462void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
463{
464 mSettings.setSymbolAlignment( alignment );
465}
466
468{
469 return mSettings.symbolAlignment();
470}
471
473{
474 return mSettings.symbolSize().height();
475}
476
478{
479 mSettings.setSymbolSize( QSizeF( mSettings.symbolSize().width(), h ) );
480}
481
483{
484 return mSettings.wmsLegendSize().width();
485}
486
488{
489 mSettings.setWmsLegendSize( QSizeF( w, mSettings.wmsLegendSize().height() ) );
490}
491
493{
494 return mSettings.wmsLegendSize().height();
495}
497{
498 mSettings.setWmsLegendSize( QSizeF( mSettings.wmsLegendSize().width(), h ) );
499}
500
502{
503 mSettings.setWrapChar( t );
504}
505
507{
508 return mSettings.wrapChar();
509}
510
512{
513 return mColumnCount;
514}
515
517{
518 mColumnCount = c;
519 mSettings.setColumnCount( c );
520}
521
523{
524 return mSettings.splitLayer();
525}
526
528{
529 mSettings.setSplitLayer( s );
530}
531
533{
534 return mSettings.equalColumnWidth();
535}
536
538{
539 mSettings.setEqualColumnWidth( s );
540}
541
543{
544 return mSettings.drawRasterStroke();
545}
546
548{
549 mSettings.setDrawRasterStroke( enabled );
550}
551
553{
554 return mSettings.rasterStrokeColor();
555}
556
558{
559 mSettings.setRasterStrokeColor( color );
560}
561
563{
564 return mSettings.rasterStrokeWidth();
565}
566
568{
569 mSettings.setRasterStrokeWidth( width );
570}
571
572
574{
576 updateFilterByMap( false );
577}
578
579bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
580{
581
582 //write general properties
583 legendElem.setAttribute( QStringLiteral( "title" ), mTitle );
584 legendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
585 legendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
586 legendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
587 legendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
588
589 legendElem.setAttribute( QStringLiteral( "boxSpace" ), QString::number( mSettings.boxSpace() ) );
590 legendElem.setAttribute( QStringLiteral( "columnSpace" ), QString::number( mSettings.columnSpace() ) );
591
592 legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
593 legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
594 legendElem.setAttribute( QStringLiteral( "maxSymbolSize" ), QString::number( mSettings.maximumSymbolSize() ) );
595 legendElem.setAttribute( QStringLiteral( "minSymbolSize" ), QString::number( mSettings.minimumSymbolSize() ) );
596
597 legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
598
599 legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
600
601 legendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterStroke() );
602 legendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterStrokeColor() ) );
603 legendElem.setAttribute( QStringLiteral( "rasterBorderWidth" ), QString::number( mSettings.rasterStrokeWidth() ) );
604
605 legendElem.setAttribute( QStringLiteral( "wmsLegendWidth" ), QString::number( mSettings.wmsLegendSize().width() ) );
606 legendElem.setAttribute( QStringLiteral( "wmsLegendHeight" ), QString::number( mSettings.wmsLegendSize().height() ) );
607 legendElem.setAttribute( QStringLiteral( "wrapChar" ), mSettings.wrapChar() );
608
609 legendElem.setAttribute( QStringLiteral( "resizeToContents" ), mSizeToContents );
610
611 if ( mMap )
612 {
613 legendElem.setAttribute( QStringLiteral( "map_uuid" ), mMap->uuid() );
614 }
615
616 QDomElement legendStyles = doc.createElement( QStringLiteral( "styles" ) );
617 legendElem.appendChild( legendStyles );
618
619 style( QgsLegendStyle::Title ).writeXml( QStringLiteral( "title" ), legendStyles, doc, context );
620 style( QgsLegendStyle::Group ).writeXml( QStringLiteral( "group" ), legendStyles, doc, context );
621 style( QgsLegendStyle::Subgroup ).writeXml( QStringLiteral( "subgroup" ), legendStyles, doc, context );
622 style( QgsLegendStyle::Symbol ).writeXml( QStringLiteral( "symbol" ), legendStyles, doc, context );
623 style( QgsLegendStyle::SymbolLabel ).writeXml( QStringLiteral( "symbolLabel" ), legendStyles, doc, context );
624
625 if ( mCustomLayerTree )
626 {
627 // if not using auto-update - store the custom layer tree
628 mCustomLayerTree->writeXml( legendElem, context );
629 }
630
631 if ( mLegendFilterByMap )
632 {
633 legendElem.setAttribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "1" ) );
634 }
635 legendElem.setAttribute( QStringLiteral( "legendFilterByAtlas" ), mFilterOutAtlas ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
636
637 return true;
638}
639
640bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
641{
642 //read general properties
643 mTitle = itemElem.attribute( QStringLiteral( "title" ) );
644 mSettings.setTitle( mTitle );
645 if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
646 {
647 mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
648 }
649 int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
650 if ( colCount < 1 ) colCount = 1;
651 mColumnCount = colCount;
652 mSettings.setColumnCount( mColumnCount );
653 mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
654 mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
655
656 const QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
657 if ( !stylesNodeList.isEmpty() )
658 {
659 const QDomNode stylesNode = stylesNodeList.at( 0 );
660 for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
661 {
662 const QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
664 style.readXml( styleElem, doc, context );
665 const QString name = styleElem.attribute( QStringLiteral( "name" ) );
667 if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
668 else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
669 else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
670 else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
671 else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
672 else continue;
673 setStyle( s, style );
674 }
675 }
676
677 //font color
678 if ( itemElem.hasAttribute( QStringLiteral( "fontColor" ) ) )
679 {
680 QColor fontClr;
681 fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
686 }
687
688 //spaces
689 mSettings.setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
690 mSettings.setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
691
692 mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
693 mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );
694
695 mSettings.setMaximumSymbolSize( itemElem.attribute( QStringLiteral( "maxSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
696 mSettings.setMinimumSymbolSize( itemElem.attribute( QStringLiteral( "minSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
697
698 mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
699
700 if ( itemElem.hasAttribute( QStringLiteral( "lineSpacing" ) ) )
701 {
702 const double spacing = itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble();
703 // line spacing *was* a fixed amount (in mm) added between each line of text.
705 // assume font sizes in points, since that was what we always had from before this method was deprecated
706 f.setLineHeight( f.size() * 0.352778 + spacing );
709
711 f.setLineHeight( f.size() * 0.352778 + spacing );
714
716 f.setLineHeight( f.size() * 0.352778 + spacing );
719
721 f.setLineHeight( f.size() * 0.352778 + spacing );
724 }
725
726 mSettings.setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
727 mSettings.setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
728 mSettings.setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
729
730 mSettings.setWrapChar( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
731
732 mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
733
734 // map
735 mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
736
737 mMapUuid.clear();
738 if ( !itemElem.attribute( QStringLiteral( "map_uuid" ) ).isEmpty() )
739 {
740 mMapUuid = itemElem.attribute( QStringLiteral( "map_uuid" ) );
741 }
742 // disconnect current map
743 setupMapConnections( mMap, false );
744 mMap = nullptr;
745
746 mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
747
748 // QGIS >= 2.6
749 QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
750 if ( layerTreeElem.isNull() )
751 layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
752
753 if ( !layerTreeElem.isNull() )
754 {
755 std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
756 if ( mLayout )
757 tree->resolveReferences( mLayout->project(), true );
758 setCustomLayerTree( tree.release() );
759 }
760 else
761 setCustomLayerTree( nullptr );
762
763 return true;
764}
765
767{
768 if ( !id().isEmpty() )
769 {
770 return id();
771 }
772
773 //if no id, default to portion of title text
774 QString text = mSettings.title();
775 if ( text.isEmpty() )
776 {
777 return tr( "<Legend>" );
778 }
779 if ( text.length() > 25 )
780 {
781 return tr( "%1…" ).arg( text.left( 25 ) );
782 }
783 else
784 {
785 return text;
786 }
787}
788
789
790void QgsLayoutItemLegend::setupMapConnections( QgsLayoutItemMap *map, bool connectSlots )
791{
792 if ( !map )
793 return;
794
795 if ( !connectSlots )
796 {
797 disconnect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
798 disconnect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
799 disconnect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
800 disconnect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
801 disconnect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
802 disconnect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
803 }
804 else
805 {
806 connect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
807 connect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
808 connect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
809 connect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
810 connect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
811 connect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
812 }
813}
814
816{
817 if ( mMap )
818 {
819 setupMapConnections( mMap, false );
820 }
821
822 mMap = map;
823
824 if ( mMap )
825 {
826 setupMapConnections( mMap, true );
827 mapThemeChanged( mMap->themeToRender( mMap->createExpressionContext() ) );
828 }
829
831}
832
833void QgsLayoutItemLegend::invalidateCurrentMap()
834{
835 setLinkedMap( nullptr );
836}
837
839{
841
842 bool forceUpdate = false;
843 //updates data defined properties and redraws item to match
844 if ( property == QgsLayoutObject::LegendTitle || property == QgsLayoutObject::AllProperties )
845 {
846 bool ok = false;
847 const QString t = mDataDefinedProperties.valueAsString( QgsLayoutObject::LegendTitle, context, mTitle, &ok );
848 if ( ok )
849 {
850 mSettings.setTitle( t );
851 forceUpdate = true;
852 }
853 }
855 {
856 bool ok = false;
857 const int cols = mDataDefinedProperties.valueAsInt( QgsLayoutObject::LegendColumnCount, context, mColumnCount, &ok );
858 if ( ok && cols >= 0 )
859 {
860 mSettings.setColumnCount( cols );
861 forceUpdate = true;
862 }
863 }
864 if ( forceUpdate )
865 {
867 update();
868 }
869
871}
872
873
874void QgsLayoutItemLegend::updateFilterByMapAndRedraw()
875{
876 updateFilterByMap( true );
877}
878
879void QgsLayoutItemLegend::setModelStyleOverrides( const QMap<QString, QString> &overrides )
880{
881 mLegendModel->setLayerStyleOverrides( overrides );
882 const QList< QgsLayerTreeLayer * > layers = mLegendModel->rootGroup()->findLayers();
883 for ( QgsLayerTreeLayer *nodeLayer : layers )
884 mLegendModel->refreshLayerLegend( nodeLayer );
885
886}
887
888void QgsLayoutItemLegend::clearLegendCachedData()
889{
890 std::function< void( QgsLayerTreeNode * ) > clearNodeCache;
891 clearNodeCache = [&]( QgsLayerTreeNode * node )
892 {
893 mLegendModel->clearCachedData( node );
894 if ( QgsLayerTree::isGroup( node ) )
895 {
897 const QList< QgsLayerTreeNode * > children = group->children();
898 for ( QgsLayerTreeNode *child : children )
899 {
900 clearNodeCache( child );
901 }
902 }
903 };
904
905 clearNodeCache( mLegendModel->rootGroup() );
906}
907
908void QgsLayoutItemLegend::mapLayerStyleOverridesChanged()
909{
910 if ( !mMap )
911 return;
912
913 // map's style has been changed, so make sure to update the legend here
914 if ( mLegendFilterByMap )
915 {
916 // legend is being filtered by map, so we need to re run the hit test too
917 // as the style overrides may also have affected the visible symbols
918 updateFilterByMap( false );
919 }
920 else
921 {
922 setModelStyleOverrides( mMap->layerStyleOverrides() );
923 }
924
926
927 updateFilterByMap( false );
928}
929
930void QgsLayoutItemLegend::mapThemeChanged( const QString &theme )
931{
932 if ( mThemeName == theme )
933 return;
934
935 mThemeName = theme;
936
937 // map's theme has been changed, so make sure to update the legend here
938 if ( mLegendFilterByMap )
939 {
940 // legend is being filtered by map, so we need to re run the hit test too
941 // as the style overrides may also have affected the visible symbols
942 updateFilterByMap( false );
943 }
944 else
945 {
946 if ( mThemeName.isEmpty() )
947 {
948 setModelStyleOverrides( QMap<QString, QString>() );
949 }
950 else
951 {
952 // get style overrides for theme
953 const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
954 setModelStyleOverrides( overrides );
955 }
956 }
957
959
961}
962
964{
965 // ask for update
966 // the actual update will take place before the redraw.
967 // This is to avoid multiple calls to the filter
968 mFilterAskedForUpdate = true;
969
970 if ( redraw )
971 update();
972}
973
974void QgsLayoutItemLegend::doUpdateFilterByMap()
975{
976 if ( mMap )
977 {
978 if ( !mThemeName.isEmpty() )
979 {
980 // get style overrides for theme
981 const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
982 mLegendModel->setLayerStyleOverrides( overrides );
983 }
984 else
985 {
986 mLegendModel->setLayerStyleOverrides( mMap->layerStyleOverrides() );
987 }
988 }
989 else
990 mLegendModel->setLayerStyleOverrides( QMap<QString, QString>() );
991
992
993 const bool filterByExpression = QgsLayerTreeUtils::hasLegendFilterExpression( *( mCustomLayerTree ? mCustomLayerTree.get() : mLayout->project()->layerTreeRoot() ) );
994
995 if ( mMap && ( mLegendFilterByMap || filterByExpression || mInAtlas ) )
996 {
997 const double dpi = mLayout->renderContext().dpi();
998
999 const QgsRectangle requestRectangle = mMap->requestedExtent();
1000
1001 QSizeF size( requestRectangle.width(), requestRectangle.height() );
1002 size *= mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() * dpi / 25.4;
1003
1004 const QgsMapSettings ms = mMap->mapSettings( requestRectangle, size, dpi, true );
1005
1006 QgsGeometry filterPolygon;
1007 if ( mInAtlas )
1008 {
1009 filterPolygon = mLayout->reportContext().currentGeometry( mMap->crs() );
1010 }
1011 mLegendModel->setLegendFilter( &ms, /* useExtent */ mInAtlas || mLegendFilterByMap, filterPolygon, /* useExpressions */ true );
1012 }
1013 else
1014 mLegendModel->setLegendFilterByMap( nullptr );
1015
1016 clearLegendCachedData();
1017 mForceResize = true;
1018}
1019
1021{
1022 return mThemeName;
1023}
1024
1026{
1027 mFilterOutAtlas = doFilter;
1028}
1029
1031{
1032 return mFilterOutAtlas;
1033}
1034
1035void QgsLayoutItemLegend::onAtlasFeature()
1036{
1037 if ( !mLayout || !mLayout->reportContext().feature().isValid() )
1038 return;
1039 mInAtlas = mFilterOutAtlas;
1041}
1042
1043void QgsLayoutItemLegend::onAtlasEnded()
1044{
1045 mInAtlas = false;
1047}
1048
1050{
1052
1053 // We only want the last scope from the map's expression context, as this contains
1054 // the map specific variables. We don't want the rest of the map's context, because that
1055 // will contain duplicate global, project, layout, etc scopes.
1056 if ( mMap )
1057 context.appendScope( mMap->createExpressionContext().popScope() );
1058
1059 QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Legend Settings" ) );
1060
1061 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_title" ), title(), true ) );
1062 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_column_count" ), columnCount(), true ) );
1063 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_split_layers" ), splitLayer(), true ) );
1064 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_wrap_string" ), wrapString(), true ) );
1065 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_by_map" ), legendFilterByMapEnabled(), true ) );
1066 scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_out_atlas" ), legendFilterOutAtlas(), true ) );
1067
1068 context.appendScope( scope );
1069 return context;
1070}
1071
1073{
1074 return MustPlaceInOwnLayer;
1075}
1076
1078{
1079 std::function<bool( QgsLayerTreeGroup *group ) >visit;
1080
1081 visit = [ =, &visit]( QgsLayerTreeGroup * group ) -> bool
1082 {
1083 const QList<QgsLayerTreeNode *> childNodes = group->children();
1084 for ( QgsLayerTreeNode *node : childNodes )
1085 {
1086 if ( QgsLayerTree::isGroup( node ) )
1087 {
1088 QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
1089 if ( !visit( nodeGroup ) )
1090 return false;
1091 }
1092 else if ( QgsLayerTree::isLayer( node ) )
1093 {
1094 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
1095 if ( !nodeLayer->patchShape().isNull() )
1096 {
1097 QgsStyleLegendPatchShapeEntity entity( nodeLayer->patchShape() );
1098 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1099 return false;
1100 }
1101 const QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->layerLegendNodes( nodeLayer );
1102 for ( QgsLayerTreeModelLegendNode *legendNode : legendNodes )
1103 {
1104 if ( QgsSymbolLegendNode *symbolNode = dynamic_cast< QgsSymbolLegendNode * >( legendNode ) )
1105 {
1106 if ( !symbolNode->patchShape().isNull() )
1107 {
1108 QgsStyleLegendPatchShapeEntity entity( symbolNode->patchShape() );
1109 if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1110 return false;
1111 }
1112 }
1113 }
1114 }
1115 }
1116 return true;
1117 };
1118 return visit( mLegendModel->rootGroup( ) );
1119}
1120
1121
1122// -------------------------------------------------------------------------
1123
1125 : QgsLayerTreeModel( rootNode, parent )
1126 , mLayoutLegend( layout )
1127{
1130 connect( this, &QgsLegendModel::dataChanged, this, &QgsLegendModel::refreshLegend );
1131}
1132
1134 : QgsLayerTreeModel( rootNode )
1135 , mLayoutLegend( layout )
1136{
1139 connect( this, &QgsLegendModel::dataChanged, this, &QgsLegendModel::refreshLegend );
1140}
1141
1142QVariant QgsLegendModel::data( const QModelIndex &index, int role ) const
1143{
1144 // handle custom layer node labels
1145
1147 QgsLayerTreeLayer *nodeLayer = QgsLayerTree::isLayer( node ) ? QgsLayerTree::toLayer( node ) : nullptr;
1148 if ( nodeLayer && ( role == Qt::DisplayRole || role == Qt::EditRole ) )
1149 {
1150 QString name = node->customProperty( QStringLiteral( "cached_name" ) ).toString();
1151 if ( !name.isEmpty() )
1152 return name;
1153
1154 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
1155
1156 //finding the first label that is stored
1157 name = nodeLayer->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1158 if ( name.isEmpty() )
1159 name = nodeLayer->name();
1160 if ( name.isEmpty() )
1161 name = node->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1162 if ( name.isEmpty() )
1163 name = node->name();
1164 if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() )
1165 {
1166 if ( vlayer && vlayer->featureCount() >= 0 )
1167 {
1168 name += QStringLiteral( " [%1]" ).arg( vlayer->featureCount() );
1169 node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1170 return name;
1171 }
1172 }
1173
1174 const bool evaluate = ( vlayer && !nodeLayer->labelExpression().isEmpty() ) || name.contains( "[%" );
1175 if ( evaluate )
1176 {
1177 QgsExpressionContext expressionContext;
1178 if ( vlayer )
1179 {
1180 connect( vlayer, &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsLegendModel::forceRefresh, Qt::UniqueConnection );
1181 // 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
1182 vlayer->countSymbolFeatures();
1183 }
1184
1185 if ( mLayoutLegend )
1186 expressionContext = mLayoutLegend->createExpressionContext();
1187
1188 const QList<QgsLayerTreeModelLegendNode *> legendnodes = layerLegendNodes( nodeLayer, false );
1189 if ( legendnodes.count() > 1 ) // evaluate all existing legend nodes but leave the name for the legend evaluator
1190 {
1191 for ( QgsLayerTreeModelLegendNode *treenode : legendnodes )
1192 {
1193 if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( treenode ) )
1194 symnode->evaluateLabel( expressionContext );
1195 }
1196 }
1197 else if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( legendnodes.first() ) )
1198 name = symnode->evaluateLabel( expressionContext );
1199 }
1200 node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1201 return name;
1202 }
1203 return QgsLayerTreeModel::data( index, role );
1204}
1205
1206Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
1207{
1208 // make the legend nodes selectable even if they are not by default
1209 if ( index2legendNode( index ) )
1210 return QgsLayerTreeModel::flags( index ) | Qt::ItemIsSelectable;
1211
1213}
1214
1215QList<QgsLayerTreeModelLegendNode *> QgsLegendModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent ) const
1216{
1217 if ( !mLegend.contains( nodeLayer ) )
1218 return QList<QgsLayerTreeModelLegendNode *>();
1219
1220 const LayerLegendData &data = mLegend[nodeLayer];
1221 QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
1222 if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
1223 lst.prepend( data.embeddedNodeInParent );
1224 return lst;
1225}
1226
1228{
1229 node->removeCustomProperty( QStringLiteral( "cached_name" ) );
1230}
1231
1232void QgsLegendModel::forceRefresh()
1233{
1234 emit refreshLegend();
1235}
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.
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
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.
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)
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.
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 setLegendFilterByMapEnabled(bool enabled)
Set whether legend items should be filtered to show just the ones visible in the associated map.
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.
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.
QgsRectangle requestedExtent() const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
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:45
QgsRenderContext & renderContext()
Returns a reference to the context's render context.
Definition: qgslayoutitem.h:72
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 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:51
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.
The QgsMapSettings class contains configuration for rendering of the map.
double scale() const
Returns the calculated map scale.
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
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:1465
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:41
void setColor(const QColor &color)
Sets the color that text will be rendered in.
void setLineHeightUnit(QgsUnitTypes::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.
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
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:3499
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:3498
#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.