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