QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 <QDomDocument>
35 #include <QDomElement>
36 #include <QPainter>
37 #include "qgsexpressioncontext.h"
38 
40  : QgsLayoutItem( layout )
41  , mLegendModel( new QgsLegendModel( layout->project()->layerTreeRoot(), this ) )
42 {
43 #if 0 //no longer required?
44  connect( &layout->atlasComposition(), &QgsAtlasComposition::renderEnded, this, &QgsLayoutItemLegend::onAtlasEnded );
45 #endif
46 
47  mTitle = mSettings.title();
48 
49  // Connect to the main layertreeroot.
50  // It serves in "auto update mode" as a medium between the main app legend and this one
51  connect( mLayout->project()->layerTreeRoot(), &QgsLayerTreeNode::customPropertyChanged, this, &QgsLayoutItemLegend::nodeCustomPropertyChanged );
52 
53  // If project colors change, we need to redraw legend, as legend symbols may rely on project colors
54  connect( mLayout->project(), &QgsProject::projectColorsChanged, this, [ = ]
55  {
57  update();
58  } );
59  connect( mLegendModel.get(), &QgsLegendModel::refreshLegend, this, &QgsLayoutItemLegend::refresh );
60 }
61 
63 {
64  return new QgsLayoutItemLegend( layout );
65 }
66 
68 {
70 }
71 
73 {
74  return QgsApplication::getThemeIcon( QStringLiteral( "/mLayoutItemLegend.svg" ) );
75 }
76 
77 QgsLayoutItem::Flags QgsLayoutItemLegend::itemFlags() const
78 {
80 }
81 
82 void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget )
83 {
84  if ( !painter )
85  return;
86 
87  if ( mFilterAskedForUpdate )
88  {
89  mFilterAskedForUpdate = false;
90  doUpdateFilterByMap();
91  }
92 
93  int dpi = painter->device()->logicalDpiX();
94  double dotsPerMM = dpi / 25.4;
95 
96  if ( mLayout )
97  {
99  mSettings.setDpi( dpi );
100  }
101  if ( mMap && mLayout )
102  {
103  mSettings.setMmPerMapUnit( mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() );
104 
105  // use a temporary QgsMapSettings to find out real map scale
106  QSizeF mapSizePixels = QSizeF( mMap->rect().width() * dotsPerMM, mMap->rect().height() * dotsPerMM );
107  QgsRectangle mapExtent = mMap->extent();
108 
109  QgsMapSettings ms = mMap->mapSettings( mapExtent, mapSizePixels, dpi, false );
110  mSettings.setMapScale( ms.scale() );
111  }
112  mInitialMapScaleCalculated = true;
113 
114  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
115  legendRenderer.setLegendSize( mForceResize && mSizeToContents ? QSize() : rect().size() );
116 
117  //adjust box if width or height is too small
118  if ( mSizeToContents )
119  {
121  QSizeF size = legendRenderer.minimumSize( &context );
122  if ( mForceResize )
123  {
124  mForceResize = false;
125 
126  //set new rect, respecting position mode and data defined size/position
127  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
128  attemptResize( newSize );
129  }
130  else if ( size.height() > rect().height() || size.width() > rect().width() )
131  {
132  //need to resize box
133  QSizeF targetSize = rect().size();
134  if ( size.height() > targetSize.height() )
135  targetSize.setHeight( size.height() );
136  if ( size.width() > targetSize.width() )
137  targetSize.setWidth( size.width() );
138 
139  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( targetSize, sizeWithUnits().units() );
140  //set new rect, respecting position mode and data defined size/position
141  attemptResize( newSize );
142  }
143  }
144 
145  QgsLayoutItem::paint( painter, itemStyle, pWidget );
146 }
147 
149 {
150  if ( !mMapUuid.isEmpty() )
151  {
152  setLinkedMap( qobject_cast< QgsLayoutItemMap * >( mLayout->itemByUuid( mMapUuid, true ) ) );
153  }
154 }
155 
157 {
159  onAtlasFeature();
160 }
161 
163 {
164  QPainter *painter = context.renderContext().painter();
165  painter->save();
166 
167  // painter is scaled to dots, so scale back to layout units
168  painter->scale( context.renderContext().scaleFactor(), context.renderContext().scaleFactor() );
169 
170  painter->setPen( QPen( QColor( 0, 0, 0 ) ) );
171 
172  if ( !mSizeToContents )
173  {
174  // set a clip region to crop out parts of legend which don't fit
175  QRectF thisPaintRect = QRectF( 0, 0, rect().width(), rect().height() );
176  painter->setClipRect( thisPaintRect );
177  }
178 
179  if ( mLayout )
180  mSettings.setDpi( mLayout->renderContext().dpi() );
181 
182  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
183  legendRenderer.setLegendSize( rect().size() );
184 
185  legendRenderer.drawLegend( context.renderContext() );
186 
187  painter->restore();
188 }
189 
191 {
192  if ( !mSizeToContents )
193  return;
194 
195  if ( !mInitialMapScaleCalculated )
196  {
197  // this is messy - but until we have painted the item we have no knowledge of the current DPI
198  // and so cannot correctly calculate the map scale. This results in incorrect size calculations
199  // for marker symbols with size in map units, causing the legends to initially expand to huge
200  // sizes if we attempt to calculate the box size first.
201  return;
202  }
203 
205  QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
206  QSizeF size = legendRenderer.minimumSize( &context );
207  QgsDebugMsg( QStringLiteral( "width = %1 height = %2" ).arg( size.width() ).arg( size.height() ) );
208  if ( size.isValid() )
209  {
210  QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( size, sizeWithUnits().units() );
211  //set new rect, respecting position mode and data defined size/position
212  attemptResize( newSize );
213  }
214 }
215 
217 {
218  mSizeToContents = enabled;
219 }
220 
222 {
223  return mSizeToContents;
224 }
225 
226 void QgsLayoutItemLegend::setCustomLayerTree( QgsLayerTree *rootGroup )
227 {
228  mLegendModel->setRootGroup( rootGroup ? rootGroup : ( mLayout ? mLayout->project()->layerTreeRoot() : nullptr ) );
229 
230  mCustomLayerTree.reset( rootGroup );
231 }
232 
233 
235 {
236  if ( autoUpdate == autoUpdateModel() )
237  return;
238 
239  setCustomLayerTree( autoUpdate ? nullptr : mLayout->project()->layerTreeRoot()->clone() );
240  adjustBoxSize();
241  updateFilterByMap( false );
242 }
243 
244 void QgsLayoutItemLegend::nodeCustomPropertyChanged( QgsLayerTreeNode *, const QString & )
245 {
246  if ( autoUpdateModel() )
247  {
248  // in "auto update" mode, some parameters on the main app legend may have been changed (expression filtering)
249  // we must then call updateItem to reflect the changes
250  updateFilterByMap( false );
251  }
252 }
253 
255 {
256  return !mCustomLayerTree;
257 }
258 
260 {
261  mLegendFilterByMap = enabled;
262  updateFilterByMap( false );
263 }
264 
265 void QgsLayoutItemLegend::setTitle( const QString &t )
266 {
267  mTitle = t;
268  mSettings.setTitle( t );
269 
270  if ( mLayout && id().isEmpty() )
271  {
272  //notify the model that the display name has changed
273  mLayout->itemsModel()->updateItemDisplayName( this );
274  }
275 }
277 {
278  return mTitle;
279 }
280 
281 Qt::AlignmentFlag QgsLayoutItemLegend::titleAlignment() const
282 {
283  return mSettings.titleAlignment();
284 }
285 
286 void QgsLayoutItemLegend::setTitleAlignment( Qt::AlignmentFlag alignment )
287 {
288  mSettings.setTitleAlignment( alignment );
289 }
290 
292 {
293  return mSettings.rstyle( s );
294 }
295 
297 {
298  return mSettings.style( s );
299 }
300 
302 {
303  mSettings.setStyle( s, style );
304 }
305 
307 {
308  return mSettings.style( s ).font();
309 }
310 
312 {
313  rstyle( s ).setFont( f );
314 }
315 
317 {
318  rstyle( s ).setMargin( margin );
319 }
320 
322 {
323  rstyle( s ).setMargin( side, margin );
324 }
325 
327 {
328  return mSettings.lineSpacing();
329 }
330 
332 {
333  mSettings.setLineSpacing( spacing );
334 }
335 
337 {
338  return mSettings.boxSpace();
339 }
340 
342 {
343  mSettings.setBoxSpace( s );
344 }
345 
347 {
348  return mSettings.columnSpace();
349 }
350 
352 {
353  mSettings.setColumnSpace( s );
354 }
355 
357 {
358  return mSettings.fontColor();
359 }
360 
362 {
363  mSettings.setFontColor( c );
364 }
365 
367 {
368  return mSettings.symbolSize().width();
369 }
370 
372 {
373  mSettings.setSymbolSize( QSizeF( w, mSettings.symbolSize().height() ) );
374 }
375 
376 void QgsLayoutItemLegend::setSymbolAlignment( Qt::AlignmentFlag alignment )
377 {
378  mSettings.setSymbolAlignment( alignment );
379 }
380 
381 Qt::AlignmentFlag QgsLayoutItemLegend::symbolAlignment() const
382 {
383  return mSettings.symbolAlignment();
384 }
385 
387 {
388  return mSettings.symbolSize().height();
389 }
390 
392 {
393  mSettings.setSymbolSize( QSizeF( mSettings.symbolSize().width(), h ) );
394 }
395 
397 {
398  return mSettings.wmsLegendSize().width();
399 }
400 
402 {
403  mSettings.setWmsLegendSize( QSizeF( w, mSettings.wmsLegendSize().height() ) );
404 }
405 
407 {
408  return mSettings.wmsLegendSize().height();
409 }
411 {
412  mSettings.setWmsLegendSize( QSizeF( mSettings.wmsLegendSize().width(), h ) );
413 }
414 
415 void QgsLayoutItemLegend::setWrapString( const QString &t )
416 {
417  mSettings.setWrapChar( t );
418 }
419 
421 {
422  return mSettings.wrapChar();
423 }
424 
426 {
427  return mColumnCount;
428 }
429 
431 {
432  mColumnCount = c;
433  mSettings.setColumnCount( c );
434 }
435 
437 {
438  return mSettings.splitLayer();
439 }
440 
442 {
443  mSettings.setSplitLayer( s );
444 }
445 
447 {
448  return mSettings.equalColumnWidth();
449 }
450 
452 {
453  mSettings.setEqualColumnWidth( s );
454 }
455 
457 {
458  return mSettings.drawRasterStroke();
459 }
460 
462 {
463  mSettings.setDrawRasterStroke( enabled );
464 }
465 
467 {
468  return mSettings.rasterStrokeColor();
469 }
470 
471 void QgsLayoutItemLegend::setRasterStrokeColor( const QColor &color )
472 {
473  mSettings.setRasterStrokeColor( color );
474 }
475 
477 {
478  return mSettings.rasterStrokeWidth();
479 }
480 
482 {
483  mSettings.setRasterStrokeWidth( width );
484 }
485 
486 
488 {
489  adjustBoxSize();
490  updateFilterByMap( false );
491 }
492 
493 bool QgsLayoutItemLegend::writePropertiesToElement( QDomElement &legendElem, QDomDocument &doc, const QgsReadWriteContext &context ) const
494 {
495 
496  //write general properties
497  legendElem.setAttribute( QStringLiteral( "title" ), mTitle );
498  legendElem.setAttribute( QStringLiteral( "titleAlignment" ), QString::number( static_cast< int >( mSettings.titleAlignment() ) ) );
499  legendElem.setAttribute( QStringLiteral( "columnCount" ), QString::number( mColumnCount ) );
500  legendElem.setAttribute( QStringLiteral( "splitLayer" ), QString::number( mSettings.splitLayer() ) );
501  legendElem.setAttribute( QStringLiteral( "equalColumnWidth" ), QString::number( mSettings.equalColumnWidth() ) );
502 
503  legendElem.setAttribute( QStringLiteral( "boxSpace" ), QString::number( mSettings.boxSpace() ) );
504  legendElem.setAttribute( QStringLiteral( "columnSpace" ), QString::number( mSettings.columnSpace() ) );
505 
506  legendElem.setAttribute( QStringLiteral( "symbolWidth" ), QString::number( mSettings.symbolSize().width() ) );
507  legendElem.setAttribute( QStringLiteral( "symbolHeight" ), QString::number( mSettings.symbolSize().height() ) );
508 
509  legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
510 
511  legendElem.setAttribute( QStringLiteral( "symbolAlignment" ), mSettings.symbolAlignment() );
512  legendElem.setAttribute( QStringLiteral( "lineSpacing" ), QString::number( mSettings.lineSpacing() ) );
513 
514  legendElem.setAttribute( QStringLiteral( "rasterBorder" ), mSettings.drawRasterStroke() );
515  legendElem.setAttribute( QStringLiteral( "rasterBorderColor" ), QgsSymbolLayerUtils::encodeColor( mSettings.rasterStrokeColor() ) );
516  legendElem.setAttribute( QStringLiteral( "rasterBorderWidth" ), QString::number( mSettings.rasterStrokeWidth() ) );
517 
518  legendElem.setAttribute( QStringLiteral( "wmsLegendWidth" ), QString::number( mSettings.wmsLegendSize().width() ) );
519  legendElem.setAttribute( QStringLiteral( "wmsLegendHeight" ), QString::number( mSettings.wmsLegendSize().height() ) );
520  legendElem.setAttribute( QStringLiteral( "wrapChar" ), mSettings.wrapChar() );
521  legendElem.setAttribute( QStringLiteral( "fontColor" ), mSettings.fontColor().name() );
522 
523  legendElem.setAttribute( QStringLiteral( "resizeToContents" ), mSizeToContents );
524 
525  if ( mMap )
526  {
527  legendElem.setAttribute( QStringLiteral( "map_uuid" ), mMap->uuid() );
528  }
529 
530  QDomElement legendStyles = doc.createElement( QStringLiteral( "styles" ) );
531  legendElem.appendChild( legendStyles );
532 
533  style( QgsLegendStyle::Title ).writeXml( QStringLiteral( "title" ), legendStyles, doc );
534  style( QgsLegendStyle::Group ).writeXml( QStringLiteral( "group" ), legendStyles, doc );
535  style( QgsLegendStyle::Subgroup ).writeXml( QStringLiteral( "subgroup" ), legendStyles, doc );
536  style( QgsLegendStyle::Symbol ).writeXml( QStringLiteral( "symbol" ), legendStyles, doc );
537  style( QgsLegendStyle::SymbolLabel ).writeXml( QStringLiteral( "symbolLabel" ), legendStyles, doc );
538 
539  if ( mCustomLayerTree )
540  {
541  // if not using auto-update - store the custom layer tree
542  mCustomLayerTree->writeXml( legendElem, context );
543  }
544 
545  if ( mLegendFilterByMap )
546  {
547  legendElem.setAttribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "1" ) );
548  }
549  legendElem.setAttribute( QStringLiteral( "legendFilterByAtlas" ), mFilterOutAtlas ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
550 
551  return true;
552 }
553 
554 bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context )
555 {
556  //read general properties
557  mTitle = itemElem.attribute( QStringLiteral( "title" ) );
558  mSettings.setTitle( mTitle );
559  if ( !itemElem.attribute( QStringLiteral( "titleAlignment" ) ).isEmpty() )
560  {
561  mSettings.setTitleAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "titleAlignment" ) ).toInt() ) );
562  }
563  int colCount = itemElem.attribute( QStringLiteral( "columnCount" ), QStringLiteral( "1" ) ).toInt();
564  if ( colCount < 1 ) colCount = 1;
565  mColumnCount = colCount;
566  mSettings.setColumnCount( mColumnCount );
567  mSettings.setSplitLayer( itemElem.attribute( QStringLiteral( "splitLayer" ), QStringLiteral( "0" ) ).toInt() == 1 );
568  mSettings.setEqualColumnWidth( itemElem.attribute( QStringLiteral( "equalColumnWidth" ), QStringLiteral( "0" ) ).toInt() == 1 );
569 
570  QDomNodeList stylesNodeList = itemElem.elementsByTagName( QStringLiteral( "styles" ) );
571  if ( !stylesNodeList.isEmpty() )
572  {
573  QDomNode stylesNode = stylesNodeList.at( 0 );
574  for ( int i = 0; i < stylesNode.childNodes().size(); i++ )
575  {
576  QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
578  style.readXml( styleElem, doc );
579  QString name = styleElem.attribute( QStringLiteral( "name" ) );
581  if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
582  else if ( name == QLatin1String( "group" ) ) s = QgsLegendStyle::Group;
583  else if ( name == QLatin1String( "subgroup" ) ) s = QgsLegendStyle::Subgroup;
584  else if ( name == QLatin1String( "symbol" ) ) s = QgsLegendStyle::Symbol;
585  else if ( name == QLatin1String( "symbolLabel" ) ) s = QgsLegendStyle::SymbolLabel;
586  else continue;
587  setStyle( s, style );
588  }
589  }
590 
591  //font color
592  QColor fontClr;
593  fontClr.setNamedColor( itemElem.attribute( QStringLiteral( "fontColor" ), QStringLiteral( "#000000" ) ) );
594  mSettings.setFontColor( fontClr );
595 
596  //spaces
597  mSettings.setBoxSpace( itemElem.attribute( QStringLiteral( "boxSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
598  mSettings.setColumnSpace( itemElem.attribute( QStringLiteral( "columnSpace" ), QStringLiteral( "2.0" ) ).toDouble() );
599 
600  mSettings.setSymbolSize( QSizeF( itemElem.attribute( QStringLiteral( "symbolWidth" ), QStringLiteral( "7.0" ) ).toDouble(), itemElem.attribute( QStringLiteral( "symbolHeight" ), QStringLiteral( "14.0" ) ).toDouble() ) );
601  mSettings.setSymbolAlignment( static_cast< Qt::AlignmentFlag >( itemElem.attribute( QStringLiteral( "symbolAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() ) );
602 
603  mSettings.setWmsLegendSize( QSizeF( itemElem.attribute( QStringLiteral( "wmsLegendWidth" ), QStringLiteral( "50" ) ).toDouble(), itemElem.attribute( QStringLiteral( "wmsLegendHeight" ), QStringLiteral( "25" ) ).toDouble() ) );
604  mSettings.setLineSpacing( itemElem.attribute( QStringLiteral( "lineSpacing" ), QStringLiteral( "1.0" ) ).toDouble() );
605 
606  mSettings.setDrawRasterStroke( itemElem.attribute( QStringLiteral( "rasterBorder" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
607  mSettings.setRasterStrokeColor( QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "rasterBorderColor" ), QStringLiteral( "0,0,0" ) ) ) );
608  mSettings.setRasterStrokeWidth( itemElem.attribute( QStringLiteral( "rasterBorderWidth" ), QStringLiteral( "0" ) ).toDouble() );
609 
610  mSettings.setWrapChar( itemElem.attribute( QStringLiteral( "wrapChar" ) ) );
611 
612  mSizeToContents = itemElem.attribute( QStringLiteral( "resizeToContents" ), QStringLiteral( "1" ) ) != QLatin1String( "0" );
613 
614  // map
615  mLegendFilterByMap = itemElem.attribute( QStringLiteral( "legendFilterByMap" ), QStringLiteral( "0" ) ).toInt();
616 
617  mMapUuid.clear();
618  if ( !itemElem.attribute( QStringLiteral( "map_uuid" ) ).isEmpty() )
619  {
620  mMapUuid = itemElem.attribute( QStringLiteral( "map_uuid" ) );
621  }
622  // disconnect current map
623  setupMapConnections( mMap, false );
624  mMap = nullptr;
625 
626  mFilterOutAtlas = itemElem.attribute( QStringLiteral( "legendFilterByAtlas" ), QStringLiteral( "0" ) ).toInt();
627 
628  // QGIS >= 2.6
629  QDomElement layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree" ) );
630  if ( layerTreeElem.isNull() )
631  layerTreeElem = itemElem.firstChildElement( QStringLiteral( "layer-tree-group" ) );
632 
633  if ( !layerTreeElem.isNull() )
634  {
635  std::unique_ptr< QgsLayerTree > tree( QgsLayerTree::readXml( layerTreeElem, context ) );
636  if ( mLayout )
637  tree->resolveReferences( mLayout->project(), true );
638  setCustomLayerTree( tree.release() );
639  }
640  else
641  setCustomLayerTree( nullptr );
642 
643  return true;
644 }
645 
647 {
648  if ( !id().isEmpty() )
649  {
650  return id();
651  }
652 
653  //if no id, default to portion of title text
654  QString text = mSettings.title();
655  if ( text.isEmpty() )
656  {
657  return tr( "<Legend>" );
658  }
659  if ( text.length() > 25 )
660  {
661  return tr( "%1…" ).arg( text.left( 25 ) );
662  }
663  else
664  {
665  return text;
666  }
667 }
668 
669 
670 void QgsLayoutItemLegend::setupMapConnections( QgsLayoutItemMap *map, bool connectSlots )
671 {
672  if ( !map )
673  return;
674 
675  if ( !connectSlots )
676  {
677  disconnect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
678  disconnect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
679  disconnect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
680  disconnect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
681  }
682  else
683  {
684  connect( map, &QObject::destroyed, this, &QgsLayoutItemLegend::invalidateCurrentMap );
685  connect( map, &QgsLayoutObject::changed, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
686  connect( map, &QgsLayoutItemMap::extentChanged, this, &QgsLayoutItemLegend::updateFilterByMapAndRedraw );
687  connect( map, &QgsLayoutItemMap::layerStyleOverridesChanged, this, &QgsLayoutItemLegend::mapLayerStyleOverridesChanged );
688  }
689 }
690 
692 {
693  if ( mMap )
694  {
695  setupMapConnections( mMap, false );
696  }
697 
698  mMap = map;
699 
700  if ( mMap )
701  {
702  setupMapConnections( mMap, true );
703  }
704 
706 
707 }
708 
709 void QgsLayoutItemLegend::invalidateCurrentMap()
710 {
711  setLinkedMap( nullptr );
712 }
713 
715 {
717 
718  bool forceUpdate = false;
719  //updates data defined properties and redraws item to match
720  if ( property == QgsLayoutObject::LegendTitle || property == QgsLayoutObject::AllProperties )
721  {
722  bool ok = false;
723  QString t = mDataDefinedProperties.valueAsString( QgsLayoutObject::LegendTitle, context, mTitle, &ok );
724  if ( ok )
725  {
726  mSettings.setTitle( t );
727  forceUpdate = true;
728  }
729  }
731  {
732  bool ok = false;
733  int cols = mDataDefinedProperties.valueAsInt( QgsLayoutObject::LegendColumnCount, context, mColumnCount, &ok );
734  if ( ok && cols >= 0 )
735  {
736  mSettings.setColumnCount( cols );
737  forceUpdate = true;
738  }
739  }
740  if ( forceUpdate )
741  {
742  adjustBoxSize();
743  update();
744  }
745 
747 }
748 
749 
750 void QgsLayoutItemLegend::updateFilterByMapAndRedraw()
751 {
752  updateFilterByMap( true );
753 }
754 
755 void QgsLayoutItemLegend::mapLayerStyleOverridesChanged()
756 {
757  if ( !mMap )
758  return;
759 
760  // map's style has been changed, so make sure to update the legend here
761  if ( mLegendFilterByMap )
762  {
763  // legend is being filtered by map, so we need to re run the hit test too
764  // as the style overrides may also have affected the visible symbols
765  updateFilterByMap( false );
766  }
767  else
768  {
769  mLegendModel->setLayerStyleOverrides( mMap->layerStyleOverrides() );
770  const QList< QgsLayerTreeLayer * > layers = mLegendModel->rootGroup()->findLayers();
771  for ( QgsLayerTreeLayer *nodeLayer : layers )
772  mLegendModel->refreshLayerLegend( nodeLayer );
773  }
774 
775  adjustBoxSize();
776  updateFilterByMap( false );
777 }
778 
780 {
781  // ask for update
782  // the actual update will take place before the redraw.
783  // This is to avoid multiple calls to the filter
784  mFilterAskedForUpdate = true;
785 
786  if ( redraw )
787  update();
788 }
789 
790 void QgsLayoutItemLegend::doUpdateFilterByMap()
791 {
792  if ( mMap )
793  mLegendModel->setLayerStyleOverrides( mMap->layerStyleOverrides() );
794  else
795  mLegendModel->setLayerStyleOverrides( QMap<QString, QString>() );
796 
797 
798  bool filterByExpression = QgsLayerTreeUtils::hasLegendFilterExpression( *( mCustomLayerTree ? mCustomLayerTree.get() : mLayout->project()->layerTreeRoot() ) );
799 
800  if ( mMap && ( mLegendFilterByMap || filterByExpression || mInAtlas ) )
801  {
802  double dpi = mLayout->renderContext().dpi();
803 
804  QgsRectangle requestRectangle = mMap->requestedExtent();
805 
806  QSizeF size( requestRectangle.width(), requestRectangle.height() );
807  size *= mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() * dpi / 25.4;
808 
809  QgsMapSettings ms = mMap->mapSettings( requestRectangle, size, dpi, true );
810 
811  QgsGeometry filterPolygon;
812  if ( mInAtlas )
813  {
814  filterPolygon = mLayout->reportContext().currentGeometry( mMap->crs() );
815  }
816  mLegendModel->setLegendFilter( &ms, /* useExtent */ mInAtlas || mLegendFilterByMap, filterPolygon, /* useExpressions */ true );
817  }
818  else
819  mLegendModel->setLegendFilterByMap( nullptr );
820 
821  mForceResize = true;
822 }
823 
825 {
826  mFilterOutAtlas = doFilter;
827 }
828 
830 {
831  return mFilterOutAtlas;
832 }
833 
834 void QgsLayoutItemLegend::onAtlasFeature()
835 {
836  if ( !mLayout->reportContext().feature().isValid() )
837  return;
838  mInAtlas = mFilterOutAtlas;
840 }
841 
842 void QgsLayoutItemLegend::onAtlasEnded()
843 {
844  mInAtlas = false;
846 }
847 
849 {
851 
852  // We only want the last scope from the map's expression context, as this contains
853  // the map specific variables. We don't want the rest of the map's context, because that
854  // will contain duplicate global, project, layout, etc scopes.
855  if ( mMap )
856  context.appendScope( mMap->createExpressionContext().popScope() );
857 
858  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Legend Settings" ) );
859 
860  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_title" ), title(), true ) );
861  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_column_count" ), columnCount(), true ) );
862  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_split_layers" ), splitLayer(), true ) );
863  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_wrap_string" ), wrapString(), true ) );
864  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_by_map" ), legendFilterByMapEnabled(), true ) );
865  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "legend_filter_out_atlas" ), legendFilterOutAtlas(), true ) );
866 
867  context.appendScope( scope );
868  return context;
869 }
870 
872 {
873  return MustPlaceInOwnLayer;
874 }
875 
876 
877 // -------------------------------------------------------------------------
879 #include "qgsvectorlayer.h"
880 #include "qgsmaplayerlegend.h"
881 
883  : QgsLayerTreeModel( rootNode, parent )
884  , mLayoutLegend( layout )
885 {
888 }
889 
891  : QgsLayerTreeModel( rootNode )
892  , mLayoutLegend( layout )
893 {
896 }
897 
898 QVariant QgsLegendModel::data( const QModelIndex &index, int role ) const
899 {
900  // handle custom layer node labels
901 
902  QgsLayerTreeNode *node = index2node( index );
903  QgsLayerTreeLayer *nodeLayer = QgsLayerTree::isLayer( node ) ? QgsLayerTree::toLayer( node ) : nullptr;
904  if ( nodeLayer && ( role == Qt::DisplayRole || role == Qt::EditRole ) )
905  {
906  QString name;
907  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() );
908 
909  //finding the first label that is stored
910  name = nodeLayer->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
911  if ( name.isEmpty() )
912  name = nodeLayer->name();
913  if ( name.isEmpty() )
914  name = node->customProperty( QStringLiteral( "legend/title-label" ) ).toString();
915  if ( name.isEmpty() )
916  name = node->name();
917  if ( nodeLayer->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toInt() )
918  {
919  if ( vlayer && vlayer->featureCount() >= 0 )
920  {
921  name += QStringLiteral( " [%1]" ).arg( vlayer->featureCount() );
922  return name;
923  }
924  }
925 
926  bool evaluate = vlayer ? !nodeLayer->labelExpression().isEmpty() : false;
927 
928  if ( evaluate || name.contains( "[%" ) )
929  {
930  QgsExpressionContext expressionContext;
931  if ( vlayer )
932  {
933  connect( vlayer, &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsLegendModel::forceRefresh, Qt::UniqueConnection );
934  // 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
935  vlayer->countSymbolFeatures();
936  }
937 
938  if ( mLayoutLegend )
939  expressionContext = mLayoutLegend->createExpressionContext();
940  else
941  expressionContext = QgsExpressionContext();
942 
943  const QList<QgsLayerTreeModelLegendNode *> legendnodes = layerLegendNodes( nodeLayer, false );
944  if ( legendnodes.count() > 1 ) // evaluate all existing legend nodes but leave the name for the legend evaluator
945  {
946  for ( QgsLayerTreeModelLegendNode *treenode : legendnodes )
947  {
948  if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( treenode ) )
949  symnode->evaluateLabel( expressionContext );
950  }
951  }
952  else if ( QgsSymbolLegendNode *symnode = qobject_cast<QgsSymbolLegendNode *>( legendnodes.first() ) )
953  name = symnode->evaluateLabel( expressionContext );
954  }
955  return name;
956  }
957  return QgsLayerTreeModel::data( index, role );
958 }
959 
960 Qt::ItemFlags QgsLegendModel::flags( const QModelIndex &index ) const
961 {
962  // make the legend nodes selectable even if they are not by default
963  if ( index2legendNode( index ) )
964  return QgsLayerTreeModel::flags( index ) | Qt::ItemIsSelectable;
965 
966  return QgsLayerTreeModel::flags( index );
967 }
968 
969 QList<QgsLayerTreeModelLegendNode *> QgsLegendModel::layerLegendNodes( QgsLayerTreeLayer *nodeLayer, bool skipNodeEmbeddedInParent ) const
970 {
971  if ( !mLegend.contains( nodeLayer ) )
972  return QList<QgsLayerTreeModelLegendNode *>();
973 
974  const LayerLegendData &data = mLegend[nodeLayer];
975  QList<QgsLayerTreeModelLegendNode *> lst( data.activeNodes );
976  if ( !skipNodeEmbeddedInParent && data.embeddedNodeInParent )
977  lst.prepend( data.embeddedNodeInParent );
978  return lst;
979 }
980 
981 void QgsLegendModel::forceRefresh()
982 {
983  emit refreshLegend();
984 }
985 
986 
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)
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...
QMap< QgsLayerTreeLayer *, LayerLegendData > mLegend
Per layer data about layer&#39;s legend nodes.
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)
double lineSpacing() const
Returns the spacing in-between lines in layout units.
double boxSpace() const
Returns the legend box space.
QgsVectorLayerFeatureCounter * countSymbolFeatures()
Count features for symbols.
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)
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
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.
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.
QString wrapChar() const
void paint(QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget) override
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
int type() const override
void setSymbolSize(QSizeF s)
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.
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:122
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.
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...
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.
Allow check boxes for legend nodes (if supported by layer&#39;s legend)
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
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns style.
void adjustBoxSize()
Sets the legend&#39;s item bounds to fit the whole legend content.
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
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.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:202
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...
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
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...
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)
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.
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.
void setDpi(int dpi)
double boxSpace() const
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)
Single scope for storing variables and functions for use within a QgsExpressionContext.
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)
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.
Style
Component of legends which can be styled.
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 setAutoUpdateModel(bool autoUpdate)
Sets whether the legend content should auto update to reflect changes in the project&#39;s layer tree...
void setColumnCount(int count)
Sets the legend column count.
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
QSizeF symbolSize() const
Contains settings and helpers relating to a render of a QgsLayoutItem.
Definition: qgslayoutitem.h:44
void setLineSpacing(double s)
QgsMapLayer * layer() const
Returns the map layer associated with this node.
void readXml(const QDomElement &elem, const QDomDocument &doc)
Reads the component&#39;s style definition from an XML element.
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)
QgsLegendStyle & rstyle(QgsLegendStyle::Style s)
Returns reference to modifiable style.
Contains information about the context of a rendering operation.
ExportLayerBehavior
Behavior of item when exporting to layered outputs.
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.
QgsCoordinateReferenceSystem crs() const
Returns coordinate reference system used for rendering the map.
void setStyle(QgsLegendStyle::Style s, const QgsLegendStyle &style)
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
void setStyleMargin(QgsLegendStyle::Style component, double margin)
Set the margin for a legend component.
void setColumnCount(int c)
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
double columnSpace() const
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...
void setRasterStrokeWidth(double width)
Sets the stroke width for the stroke drawn around raster symbol items.
void writeXml(const QString &name, QDomElement &elem, QDomDocument &doc) const
Writes the component&#39;s style definition to an XML element.
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.
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.
Symbol label (excluding icon)
double lineSpacing() const
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
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.
bool splitLayer() const
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.
void setSymbolAlignment(Qt::AlignmentFlag alignment)
Sets the alignment for placement of legend symbols.
QIcon icon() const override
Returns the item&#39;s icon.
double wmsLegendWidth() const
Returns the WMS legend width.
Allow reordering with drag&#39;n&#39;drop.
Legend group title.
void setSplitLayer(bool s)
static QColor decodeColor(const QString &str)
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:209
Layer tree node points to a map layer.
The QgsLegendRenderer class handles automatic layout and rendering of legend.
QString title() const
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.