QGIS API Documentation  3.17.0-Master (8af46bc54f)
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"
20 #include "qgslayoutitemregistry.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"
34 #include "qgsmapthemecollection.h"
35 #include "qgsstyleentityvisitor.h"
36 #include <QDomDocument>
37 #include <QDomElement>
38 #include <QPainter>
39 #include "qgsexpressioncontext.h"
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  {
59  update();
60  } );
61  connect( mLegendModel.get(), &QgsLegendModel::refreshLegend, this, &QgsLayoutItemLegend::refresh );
62 }
63 
65 {
66  return new QgsLayoutItemLegend( layout );
67 }
68 
70 {
72 }
73 
75 {
76  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemLegend.svg" ) );
77 }
78 
79 QgsLayoutItem::Flags QgsLayoutItemLegend::itemFlags() const
80 {
82 }
83 
84 void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
85 {
86  if ( !painter )
87  return;
88 
89  if ( mFilterAskedForUpdate )
90  {
91  mFilterAskedForUpdate = false;
92  doUpdateFilterByMap();
93  }
94 
95  int dpi = painter->device()->logicalDpiX();
96  double dotsPerMM = dpi / 25.4;
97 
98  if ( mLayout )
99  {
101  // no longer required, but left set for api stability
102  mSettings.setUseAdvancedEffects( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagUseAdvancedEffects );
103  mSettings.setDpi( dpi );
105  }
106  if ( mMap && mLayout )
107  {
109  // no longer required, but left set for api stability
110  mSettings.setMmPerMapUnit( mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() );
112 
113  // use a temporary QgsMapSettings to find out real map scale
114  QSizeF mapSizePixels = QSizeF( mMap->rect().width() * dotsPerMM, mMap->rect().height() * dotsPerMM );
115  QgsRectangle mapExtent = mMap->extent();
116 
117  QgsMapSettings ms = mMap->mapSettings( mapExtent, mapSizePixels, dpi, false );
118 
119  // no longer required, but left set for api stability
121  mSettings.setMapScale( ms.scale() );
123  }
124  mInitialMapScaleCalculated = true;
125 
126  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
127  legendRenderer.setLegendSize( mForceResize && mSizeToContents ? QSize() : rect().size() );
128 
129  //adjust box if width or height is too small
130  if ( mSizeToContents )
131  {
132  QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter )
134 
135  QSizeF size = legendRenderer.minimumSize( &context );
136  if ( mForceResize )
137  {
138  mForceResize = false;
139 
140  //set new rect, respecting position mode and data defined size/position
141  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
142  attemptResize( newSize );
143  }
144  else if ( size.height() > rect().height() || size.width() > rect().width() )
145  {
146  //need to resize box
147  QSizeF targetSize = rect().size();
148  if ( size.height() > targetSize.height() )
149  targetSize.setHeight( size.height() );
150  if ( size.width() > targetSize.width() )
151  targetSize.setWidth( size.width() );
152 
153  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( targetSize, sizeWithUnits().units() );
154  //set new rect, respecting position mode and data defined size/position
155  attemptResize( newSize );
156  }
157  }
158 
159  QgsLayoutItem::paint( painter, itemStyle, pWidget );
160 }
161 
163 {
164  if ( !mMapUuid.isEmpty() )
165  {
166  setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) ) );
167  }
168 }
169 
171 {
173  clearLegendCachedData();
174  onAtlasFeature();
175 }
176 
178 {
179  QPainter *painter = context.renderContext().painter();
180 
181  QgsRenderContext rc = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, painter, context.renderContext().scaleFactor() * 25.4 )
183 
184  QgsScopedQPainterState painterState( painter );
185 
186  // painter is scaled to dots, so scale back to layout units
187  painter->scale( rc.scaleFactor(), rc.scaleFactor() );
188 
189  painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
190 
191  if ( !mSizeToContents )
192  {
193  // set a clip region to crop out parts of legend which don't fit
194  QRectF thisPaintRect = QRectF( 0, 0, rect().width(), rect().height() );
195  painter->setClipRect( thisPaintRect );
196  }
197 
198  if ( mLayout )
199  {
200  // no longer required, but left for API compatibility
202  mSettings.setDpi( mLayout->renderContext().dpi() );
204  }
205 
206 
207 
208 
209  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
210  legendRenderer.setLegendSize( rect().size() );
211 
212  legendRenderer.drawLegend( rc );
213 }
214 
216 {
217  if ( !mSizeToContents )
218  return;
219 
220  if ( !mInitialMapScaleCalculated )
221  {
222  // this is messy - but until we have painted the item we have no knowledge of the current DPI
223  // and so cannot correctly calculate the map scale. This results in incorrect size calculations
224  // for marker symbols with size in map units, causing the legends to initially expand to huge
225  // sizes if we attempt to calculate the box size first.
226  return;
227  }
228 
229  QgsRenderContext context = mMap ? QgsLayoutUtils::createRenderContextForMap( mMap, nullptr ) :
231 
232  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
233  QSizeF size = legendRenderer.minimumSize( &context );
234  QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ) );
235  if ( size.isValid() )
236  {
237  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
238  //set new rect, respecting position mode and data defined size/position
239  attemptResize( newSize );
240  }
241 }
242 
244 {
245  mSizeToContents = enabled;
246 }
247 
249 {
250  return mSizeToContents;
251 }
252 
253 void QgsLayoutItemLegend::setCustomLayerTree( QgsLayerTree *rootGroup )
254 {
255  mLegendModel->setRootGroup( rootGroup ? rootGroup : ( mLayout ? mLayout->project()->layerTreeRoot() : nullptr ) );
256 
257  mCustomLayerTree.reset( rootGroup );
258 }
259 
260 
262 {
263  if ( autoUpdate == autoUpdateModel() )
264  return;
265 
266  setCustomLayerTree( autoUpdate ? nullptr : mLayout->project()->layerTreeRoot()->clone() );
267  adjustBoxSize();
268  updateFilterByMap( false );
269 }
270 
271 void QgsLayoutItemLegend::nodeCustomPropertyChanged( QgsLayerTreeNode *, const QString &key )
272 {
273  if ( key == QLatin1String( "cached_name" ) )
274  return;
275 
276  if ( autoUpdateModel() )
277  {
278  // in "auto update" mode, some parameters on the main app legend may have been changed (expression filtering)
279  // we must then call updateItem to reflect the changes
280  updateFilterByMap( false );
281  }
282 }
283 
285 {
286  return !mCustomLayerTree;
287 }
288 
290 {
291  mLegendFilterByMap = enabled;
292  updateFilterByMap( false );
293 }
294 
295 void QgsLayoutItemLegend::setTitle( const QString &t )
296 {
297  mTitle = t;
298  mSettings.setTitle( t );
299 
300  if ( mLayout && id().isEmpty() )
301  {
302  //notify the model that the display name has changed
303  mLayout->itemsModel()->updateItemDisplayName( this );
304  }
305 }
307 {
308  return mTitle;
309 }
310 
311 Qt::AlignmentFlag QgsLayoutItemLegend::titleAlignment() const
312 {
313  return mSettings.titleAlignment();
314 }
315 
316 void QgsLayoutItemLegend::setTitleAlignment( Qt::AlignmentFlag alignment )
317 {
318  mSettings.setTitleAlignment( alignment );
319 }
320 
322 {
323  return mSettings.rstyle( s );
324 }
325 
327 {
328  return mSettings.style( s );
329 }
330 
332 {
333  mSettings.setStyle( s, style );
334 }
335 
337 {
338  return mSettings.style( s ).font();
339 }
340 
342 {
343  rstyle( s ).setFont( f );
344 }
345 
347 {
348  rstyle( s ).setMargin( margin );
349 }
350 
352 {
353  rstyle( s ).setMargin( side, margin );
354 }
355 
357 {
358  return mSettings.lineSpacing();
359 }
360 
362 {
363  mSettings.setLineSpacing( spacing );
364 }
365 
367 {
368  return mSettings.boxSpace();
369 }
370 
372 {
373  mSettings.setBoxSpace( s );
374 }
375 
377 {
378  return mSettings.columnSpace();
379 }
380 
382 {
383  mSettings.setColumnSpace( s );
384 }
385 
387 {
388  return mSettings.fontColor();
389 }
390 
392 {
393  mSettings.setFontColor( c );
394 }
395 
397 {
398  return mSettings.symbolSize().width();
399 }
400 
402 {
403  mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
404 }
405 
407 {
408  return mSettings.maximumSymbolSize();
409 }
410 
412 {
413  mSettings.setMaximumSymbolSize( size );
414 }
415 
417 {
418  return mSettings.minimumSymbolSize();
419 }
420 
422 {
423  mSettings.setMinimumSymbolSize( size );
424 }
425 
426 void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
427 {
428  mSettings.setSymbolAlignment( alignment );
429 }
430 
431 Qt::AlignmentFlag QgsLayoutItemLegend::symbolAlignment() const
432 {
433  return mSettings.symbolAlignment();
434 }
435 
437 {
438  return mSettings.symbolSize().height();
439 }
440 
442 {
443  mSettings.setSymbolSize( QSizeF( mSettings.symbolSize().width(), h ) );
444 }
445 
447 {
448  return mSettings.wmsLegendSize().width();
449 }
450 
452 {
453  mSettings.setWmsLegendSize( QSizeF( w, mSettings.wmsLegendSize().height() ) );
454 }
455 
457 {
458  return mSettings.wmsLegendSize().height();
459 }
461 {
462  mSettings.setWmsLegendSize( QSizeF( mSettings.wmsLegendSize().width(), h ) );
463 }
464 
465 void QgsLayoutItemLegend::setWrapString( const QString &t )
466 {
467  mSettings.setWrapChar( t );
468 }
469 
471 {
472  return mSettings.wrapChar();
473 }
474 
476 {
477  return mColumnCount;
478 }
479 
481 {
482  mColumnCount = c;
483  mSettings.setColumnCount( c );
484 }
485 
487 {
488  return mSettings.splitLayer();
489 }
490 
492 {
493  mSettings.setSplitLayer( s );
494 }
495 
497 {
498  return mSettings.equalColumnWidth();
499 }
500 
502 {
503  mSettings.setEqualColumnWidth( s );
504 }
505 
507 {
508  return mSettings.drawRasterStroke();
509 }
510 
512 {
513  mSettings.setDrawRasterStroke( enabled );
514 }
515 
517 {
518  return mSettings.rasterStrokeColor();
519 }
520 
521 void QgsLayoutItemLegend::setRasterStrokeColor( const QColor &color )
522 {
523  mSettings.setRasterStrokeColor( color );
524 }
525 
527 {
528  return mSettings.rasterStrokeWidth();
529 }
530 
532 {
533  mSettings.setRasterStrokeWidth( width );
534 }
535 
536 
538 {
539  adjustBoxSize();
540  updateFilterByMap( false );
541 }
542 
543 bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
544 {
545 
546  //write general properties
547  legendElem.setAttribute( QStringLiteral( "title" ), mTitle );
548  legendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
549  legendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
550  legendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
551  legendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
552 
553  legendElem.setAttribute( QStringLiteral( "boxSpace" ), QString::number( mSettings.boxSpace() ) );
554  legendElem.setAttribute( QStringLiteral( "columnSpace" ), QString::number( mSettings.columnSpace() ) );
555 
556  legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
557  legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
558  legendElem.setAttribute( QStringLiteral( "maxSymbolSize" ), QString::number( mSettings.maximumSymbolSize() ) );
559  legendElem.setAttribute( QStringLiteral( "minSymbolSize" ), QString::number( mSettings.minimumSymbolSize() ) );
560 
561  legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
562 
563  legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
564  legendElem.setAttribute( QStringLiteral( "lineSpacing" ), QString::number( mSettings.lineSpacing() ) );
565 
566  legendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterStroke() );
567  legendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterStrokeColor() ) );
568  legendElem.setAttribute( QStringLiteral( "rasterBorderWidth" ), QString::number( mSettings.rasterStrokeWidth() ) );
569 
570  legendElem.setAttribute( QStringLiteral( "wmsLegendWidth" ), QString::number( mSettings.wmsLegendSize().width() ) );
571  legendElem.setAttribute( QStringLiteral( "wmsLegendHeight" ), QString::number( mSettings.wmsLegendSize().height() ) );
572  legendElem.setAttribute( QStringLiteral( "wrapChar" ), mSettings.wrapChar() );
573  legendElem.setAttribute( QStringLiteral( "fontColor" ), mSettings.fontColor().name() );
574 
575  legendElem.setAttribute( QStringLiteral( "resizeToContents" ), mSizeToContents );
576 
577  if ( mMap )
578  {
579  legendElem.setAttribute( QStringLiteral( "map_uuid" ), mMap->uuid() );
580  }
581 
582  QDomElement legendStyles = doc.createElement( QStringLiteral( "styles" ) );
583  legendElem.appendChild( legendStyles );
584 
585  style( QgsLegendStyle::Title ).writeXml( QStringLiteral( "title" ), legendStyles, doc );
586  style( QgsLegendStyle::Group ).writeXml( QStringLiteral( "group" ), legendStyles, doc );
587  style( QgsLegendStyle::Subgroup ).writeXml( QStringLiteral( "subgroup" ), legendStyles, doc );
588  style( QgsLegendStyle::Symbol ).writeXml( QStringLiteral( "symbol" ), legendStyles, doc );
589  style( QgsLegendStyle::SymbolLabel ).writeXml( QStringLiteral( "symbolLabel" ), legendStyles, doc );
590 
591  if ( mCustomLayerTree )
592  {
593  // if not using auto-update - store the custom layer tree
594  mCustomLayerTree->writeXml( legendElem, context );
595  }
596 
597  if ( mLegendFilterByMap )
598  {
599  legendElem.setAttribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "1" ) );
600  }
601  legendElem.setAttribute( QStringLiteral( "legendFilterByAtlas" ), mFilterOutAtlas ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
602 
603  return true;
604 }
605 
606 bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
607 {
608  //read general properties
609  mTitle = itemElem.attribute( QStringLiteral( "title" ) );
610  mSettings.setTitle( mTitle );
611  if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
612  {
613  mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
614  }
615  int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
616  if ( colCount < 1 ) colCount = 1;
617  mColumnCount = colCount;
618  mSettings.setColumnCount( mColumnCount );
619  mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
620  mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
621 
622  QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
623  if ( !stylesNodeList.isEmpty() )
624  {
625  QDomNode stylesNode = stylesNodeList.at( 0 );
626  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
627  {
628  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
630  style.readXml( styleElem, doc, context );
631  QString name = styleElem.attribute( QStringLiteral( "name" ) );
633  if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
634  else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
635  else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
636  else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
637  else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
638  else continue;
639  setStyle( s, style );
640  }
641  }
642 
643  //font color
644  QColor fontClr;
645  fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
646  mSettings.setFontColor( fontClr );
647 
648  //spaces
649  mSettings.setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
650  mSettings.setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
651 
652  mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
653  mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );
654 
655  mSettings.setMaximumSymbolSize( itemElem.attribute( QStringLiteral( "maxSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
656  mSettings.setMinimumSymbolSize( itemElem.attribute( QStringLiteral( "minSymbolSize" ), QStringLiteral( "0.0" ) ).toDouble() );
657 
658  mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
659  mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
660 
661  mSettings.setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
662  mSettings.setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
663  mSettings.setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
664 
665  mSettings.setWrapChar( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
666 
667  mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
668 
669  // map
670  mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
671 
672  mMapUuid.clear();
673  if ( !itemElem.attribute( QStringLiteral( "map_uuid" ) ).isEmpty() )
674  {
675  mMapUuid = itemElem.attribute( QStringLiteral( "map_uuid" ) );
676  }
677  // disconnect current map
678  setupMapConnections( mMap, false );
679  mMap = nullptr;
680 
681  mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
682 
683  // QGIS >= 2.6
684  QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
685  if ( layerTreeElem.isNull() )
686  layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
687 
688  if ( !layerTreeElem.isNull() )
689  {
690  std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
691  if ( mLayout )
692  tree->resolveReferences( mLayout->project(), true );
693  setCustomLayerTree( tree.release() );
694  }
695  else
696  setCustomLayerTree( nullptr );
697 
698  return true;
699 }
700 
702 {
703  if ( !id().isEmpty() )
704  {
705  return id();
706  }
707 
708  //if no id, default to portion of title text
709  QString text = mSettings.title();
710  if ( text.isEmpty() )
711  {
712  return tr( "<Legend>" );
713  }
714  if ( text.length() > 25 )
715  {
716  return tr( "%1…" ).arg( text.left( 25 ) );
717  }
718  else
719  {
720  return text;
721  }
722 }
723 
724 
725 void QgsLayoutItemLegend::setupMapConnections( QgsLayoutItemMap *map, bool connectSlots )
726 {
727  if ( !map )
728  return;
729 
730  if ( !connectSlots )
731  {
732  disconnect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
733  disconnect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
734  disconnect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
735  disconnect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
736  disconnect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
737  disconnect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
738  }
739  else
740  {
741  connect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
742  connect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
743  connect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
744  connect( map, &QgsLayoutItemMap::mapRotationChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
745  connect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
746  connect( map, &QgsLayoutItemMap::themeChanged, this, &QgsLayoutItemLegend::mapThemeChanged );
747  }
748 }
749 
751 {
752  if ( mMap )
753  {
754  setupMapConnections( mMap, false );
755  }
756 
757  mMap = map;
758 
759  if ( mMap )
760  {
761  setupMapConnections( mMap, true );
762  mapThemeChanged( mMap->themeToRender( mMap->createExpressionContext() ) );
763  }
764 
766 }
767 
768 void QgsLayoutItemLegend::invalidateCurrentMap()
769 {
770  setLinkedMap( nullptr );
771 }
772 
774 {
776 
777  bool forceUpdate = false;
778  //updates data defined properties and redraws item to match
779  if ( property == QgsLayoutObject::LegendTitle || property == QgsLayoutObject::AllProperties )
780  {
781  bool ok = false;
782  QString t = mDataDefinedProperties.valueAsString( QgsLayoutObject::LegendTitle, context, mTitle, &ok );
783  if ( ok )
784  {
785  mSettings.setTitle( t );
786  forceUpdate = true;
787  }
788  }
790  {
791  bool ok = false;
792  int cols = mDataDefinedProperties.valueAsInt( QgsLayoutObject::LegendColumnCount, context, mColumnCount, &ok );
793  if ( ok && cols >= 0 )
794  {
795  mSettings.setColumnCount( cols );
796  forceUpdate = true;
797  }
798  }
799  if ( forceUpdate )
800  {
801  adjustBoxSize();
802  update();
803  }
804 
806 }
807 
808 
809 void QgsLayoutItemLegend::updateFilterByMapAndRedraw()
810 {
811  updateFilterByMap( true );
812 }
813 
814 void QgsLayoutItemLegend::setModelStyleOverrides( const QMap<QString, QString> &overrides )
815 {
816  mLegendModel->setLayerStyleOverrides( overrides );
817  const QList< QgsLayerTreeLayer * > layers = mLegendModel->rootGroup()->findLayers();
818  for ( QgsLayerTreeLayer *nodeLayer : layers )
819  mLegendModel->refreshLayerLegend( nodeLayer );
820 
821 }
822 
823 void QgsLayoutItemLegend::clearLegendCachedData()
824 {
825  std::function< void( QgsLayerTreeNode * ) > clearNodeCache;
826  clearNodeCache = [&]( QgsLayerTreeNode * node )
827  {
828  mLegendModel->clearCachedData( node );
829  if ( QgsLayerTree::isGroup( node ) )
830  {
831  QgsLayerTreeGroup *group = QgsLayerTree::toGroup( node );
832  const QList< QgsLayerTreeNode * > children = group->children();
833  for ( QgsLayerTreeNode *child : children )
834  {
835  clearNodeCache( child );
836  }
837  }
838  };
839 
840  clearNodeCache( mLegendModel->rootGroup() );
841 }
842 
843 void QgsLayoutItemLegend::mapLayerStyleOverridesChanged()
844 {
845  if ( !mMap )
846  return;
847 
848  // map's style has been changed, so make sure to update the legend here
849  if ( mLegendFilterByMap )
850  {
851  // legend is being filtered by map, so we need to re run the hit test too
852  // as the style overrides may also have affected the visible symbols
853  updateFilterByMap( false );
854  }
855  else
856  {
857  setModelStyleOverrides( mMap->layerStyleOverrides() );
858  }
859 
860  adjustBoxSize();
861 
862  updateFilterByMap( false );
863 }
864 
865 void QgsLayoutItemLegend::mapThemeChanged( const QString &theme )
866 {
867  if ( mThemeName == theme )
868  return;
869 
870  mThemeName = theme;
871 
872  // map's theme has been changed, so make sure to update the legend here
873  if ( mLegendFilterByMap )
874  {
875  // legend is being filtered by map, so we need to re run the hit test too
876  // as the style overrides may also have affected the visible symbols
877  updateFilterByMap( false );
878  }
879  else
880  {
881  if ( mThemeName.isEmpty() )
882  {
883  setModelStyleOverrides( QMap<QString, QString>() );
884  }
885  else
886  {
887  // get style overrides for theme
888  const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
889  setModelStyleOverrides( overrides );
890  }
891  }
892 
893  adjustBoxSize();
894 
896 }
897 
899 {
900  // ask for update
901  // the actual update will take place before the redraw.
902  // This is to avoid multiple calls to the filter
903  mFilterAskedForUpdate = true;
904 
905  if ( redraw )
906  update();
907 }
908 
909 void QgsLayoutItemLegend::doUpdateFilterByMap()
910 {
911  if ( mMap )
912  {
913  if ( !mThemeName.isEmpty() )
914  {
915  // get style overrides for theme
916  const QMap<QString, QString> overrides = mLayout->project()->mapThemeCollection()->mapThemeStyleOverrides( mThemeName );
917  mLegendModel->setLayerStyleOverrides( overrides );
918  }
919  else
920  {
921  mLegendModel->setLayerStyleOverrides( mMap->layerStyleOverrides() );
922  }
923  }
924  else
925  mLegendModel->setLayerStyleOverrides( QMap<QString, QString>() );
926 
927 
928  bool filterByExpression = QgsLayerTreeUtils::hasLegendFilterExpression( *( mCustomLayerTree ? mCustomLayerTree.get() : mLayout->project()->layerTreeRoot() ) );
929 
930  if ( mMap && ( mLegendFilterByMap || filterByExpression || mInAtlas ) )
931  {
932  double dpi = mLayout->renderContext().dpi();
933 
934  QgsRectangle requestRectangle = mMap->requestedExtent();
935 
936  QSizeF size( requestRectangle.width(), requestRectangle.height() );
937  size *= mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() * dpi / 25.4;
938 
939  QgsMapSettings ms = mMap->mapSettings( requestRectangle, size, dpi, true );
940 
941  QgsGeometry filterPolygon;
942  if ( mInAtlas )
943  {
944  filterPolygon = mLayout->reportContext().currentGeometry( mMap->crs() );
945  }
946  mLegendModel->setLegendFilter( &ms, /* useExtent */ mInAtlas || mLegendFilterByMap, filterPolygon, /* useExpressions */ true );
947  }
948  else
949  mLegendModel->setLegendFilterByMap( nullptr );
950 
951  clearLegendCachedData();
952  mForceResize = true;
953 }
954 
956 {
957  return mThemeName;
958 }
959 
961 {
962  mFilterOutAtlas = doFilter;
963 }
964 
966 {
967  return mFilterOutAtlas;
968 }
969 
970 void QgsLayoutItemLegend::onAtlasFeature()
971 {
972  if ( !mLayout->reportContext().feature().isValid() )
973  return;
974  mInAtlas = mFilterOutAtlas;
976 }
977 
978 void QgsLayoutItemLegend::onAtlasEnded()
979 {
980  mInAtlas = false;
982 }
983 
985 {
987 
988  // We only want the last scope from the map's expression context, as this contains
989  // the map specific variables. We don't want the rest of the map's context, because that
990  // will contain duplicate global, project, layout, etc scopes.
991  if ( mMap )
992  context.appendScope( mMap->createExpressionContext().popScope() );
993 
994  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Legend Settings" ) );
995 
996  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_title" ), title(), true ) );
997  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_column_count" ), columnCount(), true ) );
998  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_split_layers" ), splitLayer(), true ) );
999  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_wrap_string" ), wrapString(), true ) );
1000  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_by_map" ), legendFilterByMapEnabled(), true ) );
1001  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_out_atlas" ), legendFilterOutAtlas(), true ) );
1002 
1003  context.appendScope( scope );
1004  return context;
1005 }
1006 
1008 {
1009  return MustPlaceInOwnLayer;
1010 }
1011 
1013 {
1014  std::function<bool( QgsLayerTreeGroup *group ) >visit;
1015 
1016  visit = [ =, &visit]( QgsLayerTreeGroup * group ) -> bool
1017  {
1018  const QList<QgsLayerTreeNode *> childNodes = group->children();
1019  for ( QgsLayerTreeNode *node : childNodes )
1020  {
1021  if ( QgsLayerTree::isGroup( node ) )
1022  {
1023  QgsLayerTreeGroup *nodeGroup = QgsLayerTree::toGroup( node );
1024  if ( !visit( nodeGroup ) )
1025  return false;
1026  }
1027  else if ( QgsLayerTree::isLayer( node ) )
1028  {
1029  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::toLayer( node );
1030  if ( !nodeLayer->patchShape().isNull() )
1031  {
1032  QgsStyleLegendPatchShapeEntity entity( nodeLayer->patchShape() );
1033  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1034  return false;
1035  }
1036  const QList<QgsLayerTreeModelLegendNode *> legendNodes = mLegendModel->layerLegendNodes( nodeLayer );
1037  for ( QgsLayerTreeModelLegendNode *legendNode : legendNodes )
1038  {
1039  if ( QgsSymbolLegendNode *symbolNode = dynamic_cast< QgsSymbolLegendNode * >( legendNode ) )
1040  {
1041  if ( !symbolNode->patchShape().isNull() )
1042  {
1043  QgsStyleLegendPatchShapeEntity entity( symbolNode->patchShape() );
1044  if ( !visitor->visit( QgsStyleEntityVisitorInterface::StyleLeaf( &entity, uuid(), displayName() ) ) )
1045  return false;
1046  }
1047  }
1048  }
1049  }
1050  }
1051  return true;
1052  };
1053  return visit( mLegendModel->rootGroup( ) );
1054 }
1055 
1056 
1057 // -------------------------------------------------------------------------
1059 #include "qgsvectorlayer.h"
1060 #include "qgsmaplayerlegend.h"
1061 
1063  : QgsLayerTreeModel( rootNode, parent )
1064  , mLayoutLegend( layout )
1065 {
1068 }
1069 
1071  : QgsLayerTreeModel( rootNode )
1072  , mLayoutLegend( layout )
1073 {
1076 }
1077 
1078 QVariant QgsLegendModel::data( const QModelIndex &index, int role ) const
1079 {
1080  // handle custom layer node labels
1081 
1082  QgsLayerTreeNode *node = index2node( index );
1083  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::isLayer( node ) ? QgsLayerTree::toLayer( node ) : nullptr;
1084  if ( nodeLayer && ( role == Qt::DisplayRole || role == Qt::EditRole ) )
1085  {
1086  QString name = node->customProperty( QStringLiteral( "cached_name" ) ).toString();
1087  if ( !name.isEmpty() )
1088  return name;
1089 
1090  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
1091 
1092  //finding the first label that is stored
1093  name = nodeLayer->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1094  if ( name.isEmpty() )
1095  name = nodeLayer->name();
1096  if ( name.isEmpty() )
1097  name = node->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
1098  if ( name.isEmpty() )
1099  name = node->name();
1100  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() )
1101  {
1102  if ( vlayer && vlayer->featureCount() >= 0 )
1103  {
1104  name += QStringLiteral( " [%1]" ).arg( vlayer->featureCount() );
1105  node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1106  return name;
1107  }
1108  }
1109 
1110  const bool evaluate = ( vlayer && !nodeLayer->labelExpression().isEmpty() ) || name.contains( "[%" );
1111  if ( evaluate )
1112  {
1113  QgsExpressionContext expressionContext;
1114  if ( vlayer )
1115  {
1116  connect( vlayer, &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsLegendModel::forceRefresh, Qt::UniqueConnection );
1117  // 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
1118  vlayer->countSymbolFeatures();
1119  }
1120 
1121  if ( mLayoutLegend )
1122  expressionContext = mLayoutLegend->createExpressionContext();
1123 
1124  const QList<QgsLayerTreeModelLegendNode *> legendnodes = layerLegendNodes( nodeLayer, false );
1125  if ( legendnodes.count() > 1 ) // evaluate all existing legend nodes but leave the name for the legend evaluator
1126  {
1127  for ( QgsLayerTreeModelLegendNode *treenode : legendnodes )
1128  {
1129  if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( treenode ) )
1130  symnode->evaluateLabel( expressionContext );
1131  }
1132  }
1133  else if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( legendnodes.first() ) )
1134  name = symnode->evaluateLabel( expressionContext );
1135  }
1136  node->setCustomProperty( QStringLiteral( "cached_name" ), name );
1137  return name;
1138  }
1139  return QgsLayerTreeModel::data( index, role );
1140 }
1141 
1142 Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
1143 {
1144  // make the legend nodes selectable even if they are not by default
1145  if ( index2legendNode( index ) )
1146  return QgsLayerTreeModel::flags( index ) | Qt::ItemIsSelectable;
1147 
1148  return QgsLayerTreeModel::flags( index );
1149 }
1150 
1151 QList<QgsLayerTreeModelLegendNode *> QgsLegendModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent ) const
1152 {
1153  if ( !mLegend.contains( nodeLayer ) )
1154  return QList<QgsLayerTreeModelLegendNode *>();
1155 
1156  const LayerLegendData &data = mLegend[nodeLayer];
1157  QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
1158  if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
1159  lst.prepend( data.embeddedNodeInParent );
1160  return lst;
1161 }
1162 
1164 {
1165  node->removeCustomProperty( QStringLiteral( "cached_name" ) );
1166 }
1167 
1168 void QgsLegendModel::forceRefresh()
1169 {
1170  emit refreshLegend();
1171 }
1172 
1173 
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
void setColumnSpace(double spacing)
Sets the legend column spacing.
bool splitLayer() const
Returns whether the legend items from a single layer can be split over multiple columns.
void setWrapChar(const QString &t)
Sets a string to use as a wrapping character.
Layer tree group node serves as a container for layers and further groups.
The class is used as a container of context for various read/write operations on other objects...
void setEqualColumnWidth(bool equalize)
Sets whether column widths should be equalized.
void setLegendSize(QSizeF s)
Sets the preferred resulting legend size.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
void readXml(const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext())
Reads the component&#39;s style definition from an XML element.
Single variable definition for use within a QgsExpressionContextScope.
void setFontColor(const QColor &color)
Sets the legend font color.
void setLegendFilterOutAtlas(bool doFilter)
When set to true, during an atlas rendering, it will filter out legend elements where features are ou...
static QgsLayerTreeLayer * toLayer(QgsLayerTreeNode *node)
Cast node to a layer.
Definition: qgslayertree.h:75
A rectangle specified with double values.
Definition: qgsrectangle.h:41
void setTitle(const QString &title)
Sets the legend title.
void setEqualColumnWidth(bool s)
Sets whether all columns should have equal widths.
QHash< QgsLayerTreeLayer *, LayerLegendData > mLegend
Per layer data about layer&#39;s legend nodes.
double lineSpacing() const
Returns the spacing in-between lines in layout units.
double boxSpace() const
Returns the legend box space.
Item model implementation based on layer tree model for layout legend.
virtual QString name() const =0
Returns name of the node.
double columnSpace() const
Returns the legend column spacing.
void setBoxSpace(double s)
Sets the legend box space (in millimeters), which is the empty margin around the inside of the legend...
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
Q_DECL_DEPRECATED void setMmPerMapUnit(double mmPerMapUnit)
void setSplitLayer(bool enabled)
Sets whether the legend items from a single layer can be split over multiple columns.
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
static bool isGroup(QgsLayerTreeNode *node)
Check whether the node is a valid group node.
Definition: qgslayertree.h:43
Base class for graphical items within a QgsLayout.
void setSymbolWidth(double width)
Sets the legend symbol width.
bool writePropertiesToElement(QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores item state within an XML DOM element.
Item must be placed in its own individual layer.
QgsLegendPatchShape patchShape() const
Returns the symbol patch shape to use when rendering the legend node symbol.
void setMaximumSymbolSize(double size)
Set the maximum symbol size for symbol (in millimeters).
QString wrapChar() const
Returns the string used as a wrapping character.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
static QgsLayerTreeGroup * toGroup(QgsLayerTreeNode *node)
Cast node to a group.
Definition: qgslayertree.h:64
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
int type() const override
void setSymbolSize(QSizeF s)
Sets the default symbol size (in millimeters) used for legend items.
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 extentChanged()
Emitted when the map&#39;s extent changes.
QgsLayoutSize sizeWithUnits() const
Returns the item&#39;s current size, including units.
QFont font() const
Returns the font used for rendering this legend component.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:797
A legend patch shape entity for QgsStyle databases.
Definition: qgsstyle.h:1323
Implementation of legend node interface for displaying preview of vector symbols and their labels and...
bool legendFilterByMapEnabled() const
Find out whether legend items are filtered to show just the ones visible in the associated map...
QgsLayerTreeModelLegendNode * embeddedNodeInParent
A legend node that is not displayed separately, its icon is instead shown within the layer node&#39;s ite...
Contains detailed styling information relating to how a layout legend should be rendered.
void updateFilterByMap(bool redraw=true)
Updates the legend content when filtered by map.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:123
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
ExportLayerBehavior exportLayerBehavior() const override
Returns the behavior of this item during exporting to layered exports (e.g.
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
void projectColorsChanged()
Emitted whenever the project&#39;s color scheme has been changed.
QString title() const
Returns the legend title.
void setStyle(QgsLegendStyle::Style component, const QgsLegendStyle &style)
Sets the style of component to style for the legend.
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
void setLegendFilterByMapEnabled(bool enabled)
Set whether legend items should be filtered to show just the ones visible in the associated map...
bool resizeToContents() const
Returns whether the legend should automatically resize to fit its contents.
double rasterStrokeWidth() const
Returns the stroke width (in layout units) for the stroke drawn around raster symbol items...
An interface for classes which can visit style entity (e.g.
int columnCount() const
Returns the legend column count.
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
virtual void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties)
Refreshes a data defined property for the item by reevaluating the property&#39;s value and redrawing the...
bool equalColumnWidth() const
Returns whether column widths should be equalized.
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
QgsLegendModel(QgsLayerTree *rootNode, QObject *parent=nullptr, QgsLayoutItemLegend *layout=nullptr)
Construct the model based on the given layer tree.
void setMaximumSymbolSize(double size)
Set the maximum symbol size for symbol (in millimeters).
Allow check boxes for legend nodes (if supported by layer&#39;s legend)
virtual bool visit(const QgsStyleEntityVisitorInterface::StyleLeaf &entity)
Called when the visitor will visit a style entity.
void setDrawRasterStroke(bool enabled)
Sets whether a stroke will be drawn around raster symbol items.
The QgsMapSettings class contains configuration for rendering of the map.
static QString encodeColor(const QColor &color)
QString displayName() const override
Gets item display name.
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
The QgsLayerTreeModel class is model implementation for Qt item views framework.
QSizeF wmsLegendSize() const
Returns the size (in millimeters) of WMS legend graphics shown in the legend.
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns the style for a legend component.
void adjustBoxSize()
Sets the legend&#39;s item bounds to fit the whole legend content.
Scoped object for saving and restoring a QPainter object&#39;s state.
virtual void invalidateCache()
Forces a deferred update of any cached image the item uses.
QgsRectangle extent() const
Returns the current map extent.
Layout graphical items for displaying a map.
void setFont(const QFont &font)
Sets the font used for rendering this legend component.
QString name() const override
Returns the layer&#39;s name.
QgsPropertyCollection mDataDefinedProperties
QList< QgsLayerTreeNode * > children()
Gets list of children of the node. Children are owned by the parent.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void draw(QgsLayoutItemRenderContext &context) override
Draws the item&#39;s contents using the specified item render context.
double symbolWidth() const
Returns the legend symbol width.
Namespace with helper functions for layer tree operations.
Definition: qgslayertree.h:32
void finalizeRestoreFromXml() override
Called after all pending items have been restored from XML.
QColor fontColor() const
Returns the legend font color.
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
Handles preparing a paint surface for the layout item and painting the item&#39;s content.
double scale() const
Returns the calculated map scale.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
static QgsLayerTreeModelLegendNode * index2legendNode(const QModelIndex &index)
Returns legend node for given index.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
Q_DECL_DEPRECATED void setMapScale(double scale)
Sets the legend map scale.
QgsRenderContext & renderContext()
Returns a reference to the context&#39;s render context.
Definition: qgslayoutitem.h:72
static QgsRenderContext createRenderContextForMap(QgsLayoutItemMap *map, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout map and painter destination.
double symbolHeight() const
Returns the legend symbol height.
QVariant data(const QModelIndex &index, int role) const override
QgsLegendStyle & rstyle(QgsLegendStyle::Style s)
Returns reference to modifiable legend style.
double rasterStrokeWidth() const
Returns the stroke width (in millimeters) for the stroke drawn around raster symbol items...
bool readPropertiesFromElement(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets item state from a DOM element.
double mapUnitsToLayoutUnits() const
Returns the conversion factor from map units to layout units.
static QgsRenderContext createRenderContextForLayout(QgsLayout *layout, QPainter *painter, double dpi=-1)
Creates a render context suitable for the specified layout and painter destination.
QPointer< QgsLayout > mLayout
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...
void writeXml(const QString &name, QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context=QgsReadWriteContext()) const
Writes the component&#39;s style definition to an XML element.
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.
void setRasterStrokeColor(const QColor &color)
Sets the stroke color for the stroke drawn around raster symbol items.
Symbol icon (excluding label)
void setTitle(const QString &t)
Sets the title for the legend, which will be rendered above all legend items.
double height() const SIP_HOLDGIL
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
static bool isLayer(const QgsLayerTreeNode *node)
Check whether the node is a valid layer node.
Definition: qgslayertree.h:53
This class is a base class for nodes in a layer tree.
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
double width() const SIP_HOLDGIL
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
Legend subgroup title.
void setMargin(Side side, double margin)
Sets the margin (in mm) for the specified side of the component.
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns legend style.
QString id() const
Returns the item&#39;s ID name.
Qt::AlignmentFlag titleAlignment() const
Returns the alignment of the legend title.
QgsLayoutItemLegend(QgsLayout *layout)
Constructor for QgsLayoutItemLegend, with the specified parent layout.
void setLineSpacing(double spacing)
Sets the spacing in-between multiple lines.
Q_DECL_DEPRECATED void setDpi(int dpi)
double boxSpace() const
Returns the legend box space (in millimeters), which is the empty margin around the inside of the leg...
QgsRectangle requestedExtent() const
Calculates the extent to request and the yShift of the top-left point in case of rotation.
Side
Margin sides.
void setFontColor(const QColor &c)
Sets the font color used for legend items.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void removeCustomProperty(const QString &key)
Remove a custom property from layer. Properties are stored in a map and saved in project file...
static bool hasLegendFilterExpression(const QgsLayerTreeGroup &group)
Test if one of the layers in a group has an expression filter.
void refreshLegend()
Emitted to refresh the legend.
void setColumnSpace(double s)
Sets the margin space between adjacent columns (in millimeters).
QgsLayerTreeModelLegendNode * legendNode(const QString &rule, QgsLayerTreeModel &model)
void setFlag(Flag f, bool on=true)
Enable or disable a model flag.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:49
void updateLegend()
Updates the model and all legend entries.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
void setWrapString(const QString &string)
Sets the legend text wrapping string.
double minimumSymbolSize() const
Returns the minimum symbol size (in mm).
Style
Component of legends which can be styled.
void setMinimumSymbolSize(double size)
Set the minimum symbol size for symbol (in millimeters).
void setStyleFont(QgsLegendStyle::Style component, const QFont &font)
Sets the style font for a legend component.
void setResizeToContents(bool enabled)
Sets whether the legend should automatically resize to fit its contents.
virtual void redraw()
Triggers a redraw (update) of the item.
void mapRotationChanged(double newRotation)
Emitted when the map&#39;s rotation changes.
void setAutoUpdateModel(bool autoUpdate)
Sets whether the legend content should auto update to reflect changes in the project&#39;s layer tree...
double minimumSymbolSize() const
Returns the minimum symbol size (in mm).
void setColumnCount(int count)
Sets the legend column count.
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
QSizeF symbolSize() const
Returns the default symbol size (in millimeters) used for legend items.
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
double maximumSymbolSize() const
Returns the maximum symbol size (in mm).
void setLineSpacing(double s)
Sets the line spacing to use between lines of legend text.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:798
static QgsLayoutItemLegend * create(QgsLayout *layout)
Returns a new legend item for the specified layout.
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...
void setWmsLegendSize(QSizeF s)
Sets the desired size (in millimeters) of WMS legend graphics shown in the legend.
QgsLegendStyle & rstyle(QgsLegendStyle::Style s)
Returns modifiable reference to the style for a legend component.
Contains information about the context of a rendering operation.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
Q_DECL_DEPRECATED void setUseAdvancedEffects(bool use)
void setLinkedMap(QgsLayoutItemMap *map)
Sets the map to associate with the legend.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsLayerTreeNode * index2node(const QModelIndex &index) const
Returns layer tree node for given index.
void setMinimumSymbolSize(double size)
Set the minimum symbol size for symbol (in millimeters).
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
void setStyle(QgsLegendStyle::Style s, const QgsLegendStyle &style)
Sets the style for a legend component.
Enable advanced effects such as blend modes.
QString wrapString() const
Returns the legend text wrapping string.
static QgsLayerTree * readXml(QDomElement &element, const QgsReadWriteContext &context)
Load the layer tree from an XML element.
double wmsLegendHeight() const
Returns the WMS legend height.
bool equalColumnWidth() const
Returns true if all columns should have equal widths.
void setStyleMargin(QgsLegendStyle::Style component, double margin)
Set the margin for a legend component.
void setColumnCount(int c)
Sets the desired minimum number of columns to show in the legend.
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
double columnSpace() const
Returns the margin space between adjacent columns (in millimeters).
virtual QString uuid() const
Returns the item identification string.
void setDrawRasterStroke(bool enabled)
Sets whether a stroke will be drawn around raster symbol items.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
bool autoUpdateModel() const
Returns whether the legend content should auto update to reflect changes in the project&#39;s layer tree...
void refreshDataDefinedProperty(QgsLayoutObject::DataDefinedProperty property=QgsLayoutObject::AllProperties) override
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
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...
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
void themeChanged(const QString &theme)
Emitted when the map&#39;s associated theme is changed.
void setWmsLegendHeight(double height)
Sets the WMS legend height.
QSizeF minimumSize(QgsRenderContext *renderContext=nullptr)
Runs the layout algorithm and returns the minimum size required for the legend.
QList< QgsLayerTreeModelLegendNode * > activeNodes
Active legend nodes.
QString themeName() const
Returns the name of the theme currently linked to the legend.
void layerStyleOverridesChanged()
Emitted when layer style overrides are changed...
void setWmsLegendWidth(double width)
Sets the WMS legend width.
Item overrides the default layout item painting method.
Flags flags() const
Returns OR-ed combination of model flags.
QgsExpressionContextScope * popScope()
Removes the last scope from the expression context and return it.
A layout item subclass for map legends.
void customPropertyChanged(QgsLayerTreeNode *node, const QString &key)
Emitted when a custom property of a node within the tree has been changed or removed.
void setSymbolHeight(double height)
Sets the legend symbol height.
QgsVectorLayerFeatureCounter * countSymbolFeatures(bool storeSymbolFids=false)
Count features for symbols.
Symbol label (excluding icon)
double lineSpacing() const
Returns the line spacing to use between lines of legend text.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:40
void setBoxSpace(double space)
Sets the legend box space.
QColor fontColor() const
Returns the font color used for legend items.
void changed()
Emitted when the object&#39;s properties change.
QgsLayoutItem::Flags itemFlags() const override
Returns the item&#39;s flags, which indicate how the item behaves.
bool legendFilterOutAtlas() const
Returns whether to filter out legend elements outside of the current atlas feature.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Represents a vector layer which manages a vector based data sets.
void clearCachedData(QgsLayerTreeNode *node) const
Clears any previously cached data for the specified node.
bool accept(QgsStyleEntityVisitorInterface *visitor) const override
Accepts the specified style entity visitor, causing it to visit all style entities associated with th...
bool splitLayer() const
Returns true if layer components can be split over multiple columns.
DataDefinedProperty
Data defined properties for different item types.
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...
void setRasterStrokeColor(const QColor &color)
Sets the stroke color for the stroke drawn around raster symbol items.
void setTitleAlignment(Qt::AlignmentFlag alignment)
Sets the alignment of the legend title.
void refresh() override
Refreshes the item, causing a recalculation of any property overrides and recalculation of its positi...
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
double maximumSymbolSize() const
Returns the maximum symbol size (in mm).
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
QIcon icon() const override
Returns the item&#39;s icon.
Contains information relating to the style entity currently being visited.
double wmsLegendWidth() const
Returns the WMS legend width.
Allow reordering with drag&#39;n&#39;drop.
Legend group title.
void setSplitLayer(bool s)
Sets whether layer components can be split over multiple columns.
static QColor decodeColor(const QString &str)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
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...
Layer tree node points to a map layer.
The QgsLegendRenderer class handles automatic layout and rendering of legend.
QString title() const
Returns the title for the legend, which will be rendered above all legend items.
All properties for item.
QMap< QString, QString > layerStyleOverrides() const
Returns stored overrides of styles for layers.
Structure that stores all data associated with one map layer.
QFont styleFont(QgsLegendStyle::Style component) const
Returns the font settings for a legend component.