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