QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgslayertreemodellegendnode.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayertreemodellegendnode.cpp
3  --------------------------------------
4  Date : August 2014
5  Copyright : (C) 2014 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7 
8  QgsWMSLegendNode : Sandro Santilli < strk at keybit dot net >
9 
10  ***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
20 
22 #include "qgslayertree.h"
23 #include "qgslayertreemodel.h"
24 #include "qgslegendsettings.h"
25 #include "qgsrasterlayer.h"
26 #include "qgsrenderer.h"
27 #include "qgssymbollayerutils.h"
28 #include "qgsimageoperation.h"
29 #include "qgsvectorlayer.h"
30 #include "qgspointcloudlayer.h"
31 #include "qgspointcloudrenderer.h"
32 #include "qgsrasterrenderer.h"
34 #include "qgsfeatureid.h"
35 #include "qgslayoutitem.h"
37 #include "qgsexpression.h"
38 #include "qgstextrenderer.h"
39 #include "qgssettings.h"
40 #include "qgsfileutils.h"
41 #include "qgsmarkersymbol.h"
42 
43 #include <QBuffer>
44 
46  : QObject( parent )
47  , mLayerNode( nodeL )
48  , mEmbeddedInParent( false )
49 {
50 }
51 
53 {
54  return qobject_cast<QgsLayerTreeModel *>( parent() );
55 }
56 
58 {
59  return Qt::ItemIsEnabled;
60 }
61 
62 bool QgsLayerTreeModelLegendNode::setData( const QVariant &value, int role )
63 {
64  Q_UNUSED( value )
65  Q_UNUSED( role )
66  return false;
67 }
68 
70 {
71  if ( mEmbeddedInParent )
72  return mLayerNode->patchSize();
73 
74  return mUserSize;
75 }
76 
78 {
79  if ( mUserSize == size )
80  return;
81 
82  mUserSize = size;
83  emit sizeChanged();
84 }
85 
87 {
88  QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
89 
90  double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
91  // itemHeight here is not really item height, it is only for symbol
92  // vertical alignment purpose, i.e. OK take single line height
93  // if there are more lines, those run under the symbol
94  double itemHeight = std::max( static_cast< double >( ctx && ctx->patchSize.height() > 0 ? ctx->patchSize.height() : settings.symbolSize().height() ), textHeight );
95 
96  ItemMetrics im;
97  im.symbolSize = drawSymbol( settings, ctx, itemHeight );
98  im.labelSize = drawSymbolText( settings, ctx, im.symbolSize );
99  return im;
100 }
101 
103 {
104  QJsonObject json = exportSymbolToJson( settings, context );
105  const QString text = data( Qt::DisplayRole ).toString();
106  json[ QStringLiteral( "title" ) ] = text;
107  return json;
108 }
109 
110 QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
111 {
112  QIcon symbolIcon = data( Qt::DecorationRole ).value<QIcon>();
113  if ( symbolIcon.isNull() )
114  return QSizeF();
115 
116  QSizeF size = settings.symbolSize();
117  if ( ctx )
118  {
119  if ( ctx->patchSize.width() > 0 )
120  size.setWidth( ctx->patchSize.width( ) );
121  if ( ctx->patchSize.height() > 0 )
122  size.setHeight( ctx->patchSize.height( ) );
123  }
124 
125  if ( ctx && ctx->painter )
126  {
127  switch ( settings.symbolAlignment() )
128  {
129  case Qt::AlignLeft:
130  default:
131  symbolIcon.paint( ctx->painter,
132  static_cast< int >( ctx->columnLeft ),
133  static_cast< int >( ctx->top + ( itemHeight - size.height() ) / 2 ),
134  static_cast< int >( size.width() ),
135  static_cast< int >( size.height() ) );
136  break;
137 
138  case Qt::AlignRight:
139  symbolIcon.paint( ctx->painter,
140  static_cast< int >( ctx->columnRight - size.width() ),
141  static_cast< int >( ctx->top + ( itemHeight - size.height() ) / 2 ),
142  static_cast< int >( size.width() ),
143  static_cast< int >( size.height() ) );
144  break;
145  }
146  }
147  return size;
148 }
149 
151 {
152  const QIcon icon = data( Qt::DecorationRole ).value<QIcon>();
153  if ( icon.isNull() )
154  return QJsonObject();
155 
156  const QImage image( icon.pixmap( settings.symbolSize().width(), settings.symbolSize().height() ).toImage() );
157  QByteArray byteArray;
158  QBuffer buffer( &byteArray );
159  image.save( &buffer, "PNG" );
160  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
161 
162  QJsonObject json;
163  json[ QStringLiteral( "icon" ) ] = base64;
164  return json;
165 }
166 
167 QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const
168 {
169  QSizeF labelSize( 0, 0 );
170 
171  QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
172  double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
173  double textDescent = settings.fontDescentMillimeters( symbolLabelFont );
174 
175  QgsExpressionContext tempContext;
176 
177  const QStringList lines = settings.evaluateItemText( data( Qt::DisplayRole ).toString(), ctx && ctx->context ? ctx->context->expressionContext() : tempContext );
178 
179  labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );
180 
181  double labelXMin = 0.0;
182  double labelXMax = 0.0;
183  double labelY = 0.0;
184  if ( ctx && ctx->painter )
185  {
186  ctx->painter->setPen( settings.fontColor() );
187  switch ( settings.symbolAlignment() )
188  {
189  case Qt::AlignLeft:
190  default:
191  labelXMin = ctx->columnLeft + std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
194  labelXMax = ctx->columnRight;
195  break;
196 
197  case Qt::AlignRight:
198  labelXMin = ctx->columnLeft;
199  // NOTE -- while the below calculations use the flipped margins from the style, that's only done because
200  // those are the only margins we expose and use for now! (and we expose them as generic margins, not side-specific
201  // ones) TODO when/if we expose other margin settings, these should be reversed...
202  labelXMax = ctx->columnRight - std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
205  break;
206  }
207 
208  labelY = ctx->top;
209 
210  // Vertical alignment of label with symbol
211  if ( labelSize.height() < symbolSize.height() )
212  labelY += symbolSize.height() / 2 - labelSize.height() / 2; // label centered with symbol
213 
214  labelY += textHeight;
215  }
216 
217  for ( QStringList::ConstIterator itemPart = lines.constBegin(); itemPart != lines.constEnd(); ++itemPart )
218  {
219  const double lineWidth = settings.textWidthMillimeters( symbolLabelFont, *itemPart );
220  labelSize.rwidth() = std::max( lineWidth, double( labelSize.width() ) );
221 
222  if ( ctx && ctx->painter )
223  {
224  switch ( settings.style( QgsLegendStyle::SymbolLabel ).alignment() )
225  {
226  case Qt::AlignLeft:
227  default:
228  settings.drawText( ctx->painter, labelXMin, labelY, *itemPart, symbolLabelFont );
229  break;
230 
231  case Qt::AlignRight:
232  settings.drawText( ctx->painter, labelXMax - lineWidth, labelY, *itemPart, symbolLabelFont );
233  break;
234 
235  case Qt::AlignHCenter:
236  settings.drawText( ctx->painter, labelXMin + ( labelXMax - labelXMin - lineWidth ) / 2.0, labelY, *itemPart, symbolLabelFont );
237  break;
238  }
239 
240  if ( itemPart != ( lines.end() - 1 ) )
241  labelY += textDescent + settings.lineSpacing() + textHeight;
242  }
243  }
244 
245  return labelSize;
246 }
247 
249 {
250  checkAll( true );
251 }
252 
254 {
255  checkAll( false );
256 }
257 
259 {
260  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ) )
261  {
262  if ( !vlayer->renderer() )
263  return;
264 
265  const QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems();
266  for ( const auto &item : symbolList )
267  {
268  vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), ! vlayer->renderer()->legendSymbolItemChecked( item.ruleKey() ) );
269  }
270 
271  emit dataChanged();
272  vlayer->emitStyleChanged();
273  vlayer->triggerRepaint();
274  }
275  else if ( QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( mLayerNode->layer() ) )
276  {
277  if ( !pclayer->renderer() )
278  return;
279 
280  const QStringList ruleKeys = pclayer->renderer()->legendRuleKeys();
281  for ( const QString &rule : ruleKeys )
282  {
283  pclayer->renderer()->checkLegendItem( rule, !pclayer->renderer()->legendItemChecked( rule ) );
284  }
285 
286  emit dataChanged();
287  pclayer->emitStyleChanged();
288  pclayer->triggerRepaint();
289  }
290 }
291 
292 // -------------------------------------------------------------------------
293 
296 
298  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
299  , mItem( item )
300  , mSymbolUsesMapUnits( false )
301 {
302  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
303  mIconSize = QSize( iconSize, iconSize );
304 
305  if ( MINIMUM_SIZE < 0 )
306  {
307  // it's FAR too expensive to construct a QgsSettings object for every symbol node, especially for complex
308  // projects. So only read the valid size ranges once, and store them for subsequent use
309  QgsSettings settings;
310  MINIMUM_SIZE = settings.value( "/qgis/legendsymbolMinimumSize", 0.5 ).toDouble();
311  MAXIMUM_SIZE = settings.value( "/qgis/legendsymbolMaximumSize", 20.0 ).toDouble();
312  }
313 
314  updateLabel();
315  if ( QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( nodeLayer->layer() ) )
316  connect( vl, &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsSymbolLegendNode::updateLabel );
317 
318  connect( nodeLayer, &QObject::destroyed, this, [ = ]() { mLayerNode = nullptr; } );
319 
320  if ( const QgsSymbol *symbol = mItem.symbol() )
321  {
322  mSymbolUsesMapUnits = symbol->usesMapUnits();
323  }
324 }
325 
326 Qt::ItemFlags QgsSymbolLegendNode::flags() const
327 {
328  if ( mItem.isCheckable() )
329  return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
330  else
331  return Qt::ItemIsEnabled;
332 }
333 
334 
336 {
337  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
338  return minimumIconSize( context.get() );
339 }
340 
342 {
343  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
344  const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 );
345  QSize minSz( iconSize, iconSize );
346  if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Marker )
347  {
348  // unusued width, height variables
349  double width = 0.0;
350  double height = 0.0;
351  std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) );
353  QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( largeIconSize, largeIconSize ), 0,
354  context ).toImage(),
355  minSz,
356  true ).size();
357  }
358  else if ( mItem.symbol() && mItem.symbol()->type() == Qgis::SymbolType::Line )
359  {
360  double width = 0.0;
361  double height = 0.0;
362  std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context, width, height ) );
364  QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), QSize( minSz.width(), largeIconSize ), 0,
365  context ).toImage(),
366  minSz,
367  true ).size();
368  }
369 
370  if ( !mTextOnSymbolLabel.isEmpty() && context )
371  {
372  double w = QgsTextRenderer::textWidth( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel );
373  double h = QgsTextRenderer::textHeight( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel, QgsTextRenderer::Point );
374  int wInt = ceil( w ), hInt = ceil( h );
375  if ( wInt > minSz.width() ) minSz.setWidth( wInt );
376  if ( hInt > minSz.height() ) minSz.setHeight( hInt );
377  }
378 
379  return minSz;
380 }
381 
383 {
384  return mItem.symbol();
385 }
386 
388 {
389  QString label;
390  if ( mEmbeddedInParent )
391  {
392  QVariant legendlabel = mLayerNode->customProperty( QStringLiteral( "legend/title-label" ) );
393  QString layerName = legendlabel.isNull() ? mLayerNode->name() : legendlabel.toString();
394  label = mUserLabel.isEmpty() ? layerName : mUserLabel;
395  }
396  else
397  label = mUserLabel.isEmpty() ? mItem.label() : mUserLabel;
398  return label;
399 }
400 
402 {
403  if ( mEmbeddedInParent )
404  {
405  return mLayerNode->patchShape();
406  }
407  else
408  {
409  return mPatchShape;
410  }
411 }
412 
414 {
415  mPatchShape = shape;
416 }
417 
419 {
420  return mCustomSymbol.get();
421 }
422 
424 {
425  mCustomSymbol.reset( symbol );
426 }
427 
429 {
430  if ( !symbol )
431  return;
432 
433  std::unique_ptr< QgsSymbol > s( symbol ); // this method takes ownership of symbol
434  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
435  if ( !vlayer || !vlayer->renderer() )
436  return;
437 
438  mItem.setSymbol( s.get() ); // doesn't transfer ownership
439  vlayer->renderer()->setLegendSymbolItem( mItem.ruleKey(), s.release() ); // DOES transfer ownership!
440 
441  mPixmap = QPixmap();
442 
443  emit dataChanged();
444  vlayer->triggerRepaint();
445 }
446 
448 {
449  double scale = 0.0;
450  double mupp = 0.0;
451  int dpi = 0;
452  if ( auto *lModel = model() )
453  lModel->legendMapViewData( &mupp, &dpi, &scale );
454 
455  if ( qgsDoubleNear( mupp, 0.0 ) || dpi == 0 || qgsDoubleNear( scale, 0.0 ) )
456  return nullptr;
457 
458  // setup temporary render context
459  std::unique_ptr<QgsRenderContext> context = std::make_unique<QgsRenderContext>( );
460  context->setScaleFactor( dpi / 25.4 );
461  context->setRendererScale( scale );
462  context->setMapToPixel( QgsMapToPixel( mupp ) );
463  context->setFlag( QgsRenderContext::Antialiasing, true );
464  context->setFlag( QgsRenderContext::RenderSymbolPreview, true );
465  return context.release();
466 }
467 
468 void QgsLayerTreeModelLegendNode::checkAll( bool state )
469 {
470  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ) )
471  {
472  if ( !vlayer->renderer() )
473  return;
474 
475  const QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems();
476  for ( const auto &item : symbolList )
477  {
478  vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), state );
479  }
480 
481  emit dataChanged();
482  vlayer->emitStyleChanged();
483  vlayer->triggerRepaint();
484  }
485  else if ( QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( mLayerNode->layer() ) )
486  {
487  if ( !pclayer->renderer() )
488  return;
489 
490  const QStringList ruleKeys = pclayer->renderer()->legendRuleKeys();
491  for ( const QString &rule : ruleKeys )
492  {
493  pclayer->renderer()->checkLegendItem( rule, state );
494  }
495 
496  emit dataChanged();
497  pclayer->emitStyleChanged();
498  pclayer->triggerRepaint();
499  }
500 }
501 
502 QVariant QgsSymbolLegendNode::data( int role ) const
503 {
504  if ( role == Qt::DisplayRole )
505  {
506  return mLabel;
507  }
508  else if ( role == Qt::EditRole )
509  {
510  return mUserLabel.isEmpty() ? mItem.label() : mUserLabel;
511  }
512  else if ( role == Qt::DecorationRole )
513  {
514  if ( mPixmap.isNull() || mPixmap.size() != mIconSize )
515  {
516  QPixmap pix;
517  if ( mItem.symbol() )
518  {
519  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
520 
521  // unusued width, height variables
522  double width = 0.0;
523  double height = 0.0;
524  std::unique_ptr<QgsSymbol> symbol( QgsSymbolLayerUtils::restrictedSizeSymbol( mItem.symbol(), MINIMUM_SIZE, MAXIMUM_SIZE, context.get(), width, height ) );
525  pix = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol ? symbol.get() : mItem.symbol(), mIconSize, 0, context.get() );
526 
527  if ( !mTextOnSymbolLabel.isEmpty() && context )
528  {
529  QPainter painter( &pix );
530  painter.setRenderHint( QPainter::Antialiasing );
531  context->setPainter( &painter );
532  QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context ) );
533  qreal yBaselineVCenter = ( mIconSize.height() + fm.ascent() - fm.descent() ) / 2;
534  QgsTextRenderer::drawText( QPointF( mIconSize.width() / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
535  QStringList() << mTextOnSymbolLabel, *context, mTextOnSymbolTextFormat );
536  }
537  }
538  else
539  {
540  pix = QPixmap( mIconSize );
541  pix.fill( Qt::transparent );
542  }
543 
544  mPixmap = pix;
545  }
546  return mPixmap;
547  }
548  else if ( role == Qt::CheckStateRole )
549  {
550  if ( !mItem.isCheckable() )
551  return QVariant();
552 
553  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() ) )
554  {
555  if ( !vlayer->renderer() )
556  return QVariant();
557 
558  return vlayer->renderer()->legendSymbolItemChecked( mItem.ruleKey() ) ? Qt::Checked : Qt::Unchecked;
559  }
560  }
561  else if ( role == RuleKeyRole )
562  {
563  return mItem.ruleKey();
564  }
565  else if ( role == ParentRuleKeyRole )
566  {
567  return mItem.parentRuleKey();
568  }
570  {
572  }
573 
574  return QVariant();
575 }
576 
577 bool QgsSymbolLegendNode::setData( const QVariant &value, int role )
578 {
579  if ( role != Qt::CheckStateRole )
580  return false;
581 
582  if ( !mItem.isCheckable() )
583  return false;
584 
585  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
586  if ( !vlayer || !vlayer->renderer() )
587  return false;
588 
589  vlayer->renderer()->checkLegendSymbolItem( mItem.ruleKey(), value == Qt::Checked );
590 
591  emit dataChanged();
592  vlayer->emitStyleChanged();
593 
594  vlayer->triggerRepaint();
595 
596  return true;
597 }
598 
599 
600 
601 QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
602 {
603  QgsSymbol *s = mCustomSymbol ? mCustomSymbol.get() : mItem.symbol();
604  if ( !s )
605  {
606  return QSizeF();
607  }
608 
609  // setup temporary render context
610  QgsRenderContext *context = nullptr;
611  std::unique_ptr< QgsRenderContext > tempRenderContext;
613  if ( ctx && ctx->context )
614  context = ctx->context;
615  else
616  {
617  tempRenderContext = std::make_unique< QgsRenderContext >();
618  // QGIS 4.0 - make ItemContext compulsory, so we don't have to construct temporary render contexts here
620  tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
621  tempRenderContext->setRendererScale( settings.mapScale() );
622  tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
623  tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
625  tempRenderContext->setForceVectorOutput( true );
626  tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );
627 
628  // setup a minimal expression context
629  QgsExpressionContext expContext;
631  tempRenderContext->setExpressionContext( expContext );
632  context = tempRenderContext.get();
633  }
634 
635  //Consider symbol size for point markers
636  const double desiredHeight = ctx && ctx->patchSize.height() > 0 ? ctx->patchSize.height() : settings.symbolSize().height();
637  const double desiredWidth = ctx && ctx->patchSize.width() > 0 ? ctx->patchSize.width() : settings.symbolSize().width();
638  double height = desiredHeight;
639  double width = desiredWidth;
640 
641  //Center small marker symbols
642  double widthOffset = 0;
643  double heightOffset = 0;
644 
645  double maxSymbolSize = settings.maximumSymbolSize();
646  double minSymbolSize = settings.minimumSymbolSize();
647 
648  if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
649  {
650  double size = markerSymbol->size( *context ) / context->scaleFactor();
651  height = size;
652  width = size;
653  }
654 
655  std::unique_ptr<QgsSymbol> minMaxSizeSymbol( QgsSymbolLayerUtils::restrictedSizeSymbol( s, minSymbolSize, maxSymbolSize, context, width, height ) );
656  if ( minMaxSizeSymbol )
657  {
658  s = minMaxSizeSymbol.get();
659  }
660 
661  if ( s->type() == Qgis::SymbolType::Marker )
662  {
663  if ( width < desiredWidth )
664  {
665  widthOffset = ( desiredWidth - width ) / 2.0;
666  }
667  if ( height < desiredHeight )
668  {
669  heightOffset = ( desiredHeight - height ) / 2.0;
670  }
671  }
672  if ( ctx && ctx->painter )
673  {
674  double currentYCoord = ctx->top + ( itemHeight - desiredHeight ) / 2;
675  QPainter *p = ctx->painter;
676 
677  //setup painter scaling to dots so that raster symbology is drawn to scale
678  double dotsPerMM = context->scaleFactor();
679 
680  int opacity = 255;
681  if ( QgsMapLayer *layer = layerNode()->layer() )
682  opacity = static_cast<int >( std::round( 255 * layer->opacity() ) );
683 
684  QgsScopedQPainterState painterState( p );
685  context->setPainterFlagsUsingContext( p );
686 
687  switch ( settings.symbolAlignment() )
688  {
689  case Qt::AlignLeft:
690  default:
691  p->translate( ctx->columnLeft + widthOffset, currentYCoord + heightOffset );
692  break;
693  case Qt::AlignRight:
694  p->translate( ctx->columnRight - widthOffset - width, currentYCoord + heightOffset );
695  break;
696  }
697 
698  p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
700  // QGIS 4.0 -- ctx->context will be mandatory
701  const bool useAdvancedEffects = ctx->context ? ctx->context->flags() & QgsRenderContext::UseAdvancedEffects : settings.useAdvancedEffects();
703  if ( opacity != 255 && useAdvancedEffects )
704  {
705  const int maxBleed = static_cast< int >( std::ceil( QgsSymbolLayerUtils::estimateMaxSymbolBleed( s, *context ) ) );
706 
707  //semi transparent layer, so need to draw symbol to an image (to flatten it first)
708  //create image which is same size as legend rect, in case symbol bleeds outside its allotted space
709  const QSize symbolSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast<int >( std::round( height * dotsPerMM ) ) );
710  const QSize tempImageSize( symbolSize.width() + maxBleed * 2, symbolSize.height() + maxBleed * 2 );
711  QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
712  tempImage.fill( Qt::transparent );
713  QPainter imagePainter( &tempImage );
714  context->setPainterFlagsUsingContext( &imagePainter );
715 
716  context->setPainter( &imagePainter );
717  imagePainter.translate( maxBleed, maxBleed );
718  s->drawPreviewIcon( &imagePainter, symbolSize, context, false, nullptr, &patchShape );
719  imagePainter.translate( -maxBleed, -maxBleed );
720  context->setPainter( ctx->painter );
721  //reduce opacity of image
722  imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
723  imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
724  imagePainter.end();
725  //draw rendered symbol image
726  p->drawImage( -maxBleed, -maxBleed, tempImage );
727  }
728  else
729  {
730  s->drawPreviewIcon( p, QSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast< int >( std::round( height * dotsPerMM ) ) ), context, false, nullptr, &patchShape );
731  }
732 
733  if ( !mTextOnSymbolLabel.isEmpty() )
734  {
735  QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context ) );
736  qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
737  QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
738  QStringList() << mTextOnSymbolLabel, *context, mTextOnSymbolTextFormat );
739  }
740  }
741 
742  return QSizeF( std::max( width + 2 * widthOffset, static_cast< double >( desiredWidth ) ),
743  std::max( height + 2 * heightOffset, static_cast< double >( desiredHeight ) ) );
744 }
745 
746 QJsonObject QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context ) const
747 {
748  const QgsSymbol *s = mCustomSymbol ? mCustomSymbol.get() : mItem.symbol();
749  if ( !s )
750  {
751  return QJsonObject();
752  }
753 
754 
755  QgsRenderContext ctx;
756  // QGIS 4.0 - use render context directly here, and note in the dox that the context must be correctly setup
758  ctx.setScaleFactor( settings.dpi() / 25.4 );
759  ctx.setRendererScale( settings.mapScale() );
760  ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
761  ctx.setForceVectorOutput( true );
764 
766 
767  // ensure that a minimal expression context is available
768  QgsExpressionContext expContext = context.expressionContext();
770  ctx.setExpressionContext( expContext );
771 
772  const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), minimumIconSize(), 0, &ctx );
773  QImage img( pix.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
774 
775  int opacity = 255;
776  if ( QgsMapLayer *layer = layerNode()->layer() )
777  opacity = ( 255 * layer->opacity() );
778 
779  if ( opacity != 255 )
780  {
781  QPainter painter;
782  painter.begin( &img );
783  painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
784  painter.fillRect( pix.rect(), QColor( 0, 0, 0, opacity ) );
785  painter.end();
786  }
787 
788  QByteArray byteArray;
789  QBuffer buffer( &byteArray );
790  img.save( &buffer, "PNG" );
791  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
792 
793  QJsonObject json;
794  json[ QStringLiteral( "icon" ) ] = base64;
795  if ( mItem.scaleMaxDenom() > 0 )
796  {
797  json[ QStringLiteral( "scaleMaxDenom" ) ] = mItem.scaleMaxDenom();
798  }
799  if ( mItem.scaleMinDenom() > 0 )
800  {
801  json[ QStringLiteral( "scaleMinDenom" ) ] = mItem.scaleMinDenom();
802  }
803  mItem.scaleMaxDenom();
804  return json;
805 }
806 
808 {
810  updateLabel();
811 }
812 
813 
815 {
816  if ( mSymbolUsesMapUnits )
817  {
818  mPixmap = QPixmap();
819  emit dataChanged();
820  }
821 }
822 
823 
824 void QgsSymbolLegendNode::updateLabel()
825 {
826  if ( !mLayerNode )
827  return;
828 
829  bool showFeatureCount = mLayerNode->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toBool();
830  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
831  mLabel = symbolLabel();
832 
833  if ( showFeatureCount && vl )
834  {
835  qlonglong count = mEmbeddedInParent ? vl->featureCount() : vl->featureCount( mItem.ruleKey() ) ;
836  mLabel += QStringLiteral( " [%1]" ).arg( count != -1 ? QLocale().toString( count ) : tr( "N/A" ) );
837  }
838 
839  emit dataChanged();
840 }
841 
842 QString QgsSymbolLegendNode::evaluateLabel( const QgsExpressionContext &context, const QString &label )
843 {
844  if ( !mLayerNode )
845  return QString();
846 
847  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
848 
849  if ( vl )
850  {
851  QgsExpressionContext contextCopy = QgsExpressionContext( context );
852  QgsExpressionContextScope *symbolScope = createSymbolScope();
853  contextCopy.appendScope( symbolScope );
854  contextCopy.appendScope( vl->createExpressionContextScope() );
855 
856  if ( label.isEmpty() )
857  {
858  if ( ! mLayerNode->labelExpression().isEmpty() )
859  mLabel = QgsExpression::replaceExpressionText( "[%" + mLayerNode->labelExpression() + "%]", &contextCopy );
860  else if ( mLabel.contains( "[%" ) )
861  {
862  const QString symLabel = symbolLabel();
863  mLabel = QgsExpression::replaceExpressionText( symLabel, &contextCopy );
864  }
865  return mLabel;
866  }
867  else
868  {
869  QString eLabel;
870  if ( ! mLayerNode->labelExpression().isEmpty() )
871  eLabel = QgsExpression::replaceExpressionText( label + "[%" + mLayerNode->labelExpression() + "%]", &contextCopy );
872  else if ( label.contains( "[%" ) )
873  eLabel = QgsExpression::replaceExpressionText( label, &contextCopy );
874  return eLabel;
875  }
876  }
877  return mLabel;
878 }
879 
880 QgsExpressionContextScope *QgsSymbolLegendNode::createSymbolScope() const
881 {
882  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
883 
884  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Symbol scope" ) );
885  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_label" ), symbolLabel().remove( "[%" ).remove( "%]" ), true ) );
886  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_id" ), mItem.ruleKey(), true ) );
887  if ( vl )
888  {
889  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_count" ), QVariant::fromValue( vl->featureCount( mItem.ruleKey() ) ), true ) );
890  }
891  return scope;
892 }
893 
894 // -------------------------------------------------------------------------
895 
896 
897 QgsSimpleLegendNode::QgsSimpleLegendNode( QgsLayerTreeLayer *nodeLayer, const QString &label, const QIcon &icon, QObject *parent, const QString &key )
898  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
899  , mLabel( label )
900  , mIcon( icon )
901  , mKey( key )
902 {
903 }
904 
905 QVariant QgsSimpleLegendNode::data( int role ) const
906 {
907  if ( role == Qt::DisplayRole || role == Qt::EditRole )
908  return mUserLabel.isEmpty() ? mLabel : mUserLabel;
909  else if ( role == Qt::DecorationRole )
910  return mIcon;
911  else if ( role == RuleKeyRole && !mKey.isEmpty() )
912  return mKey;
915  else
916  return QVariant();
917 }
918 
919 
920 // -------------------------------------------------------------------------
921 
922 QgsImageLegendNode::QgsImageLegendNode( QgsLayerTreeLayer *nodeLayer, const QImage &img, QObject *parent )
923  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
924  , mImage( img )
925 {
926 }
927 
928 QVariant QgsImageLegendNode::data( int role ) const
929 {
930  if ( role == Qt::DecorationRole )
931  {
932  return QPixmap::fromImage( mImage );
933  }
934  else if ( role == Qt::SizeHintRole )
935  {
936  return mImage.size();
937  }
939  {
941  }
942  return QVariant();
943 }
944 
945 QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
946 {
947  Q_UNUSED( itemHeight )
948 
949  if ( ctx && ctx->painter )
950  {
951  switch ( settings.symbolAlignment() )
952  {
953  case Qt::AlignLeft:
954  default:
955  ctx->painter->drawImage( QRectF( ctx->columnLeft, ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
956  mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
957  break;
958 
959  case Qt::AlignRight:
960  ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
961  mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
962  break;
963  }
964  }
965  return settings.wmsLegendSize();
966 }
967 
969 {
970  QByteArray byteArray;
971  QBuffer buffer( &byteArray );
972  mImage.save( &buffer, "PNG" );
973  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
974 
975  QJsonObject json;
976  json[ QStringLiteral( "icon" ) ] = base64;
977  return json;
978 }
979 
980 // -------------------------------------------------------------------------
981 
982 QgsRasterSymbolLegendNode::QgsRasterSymbolLegendNode( QgsLayerTreeLayer *nodeLayer, const QColor &color, const QString &label, QObject *parent, bool isCheckable, const QString &ruleKey )
983  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
984  , mColor( color )
985  , mLabel( label )
986  , mCheckable( isCheckable )
987  , mRuleKey( ruleKey )
988 {
989 }
990 
991 Qt::ItemFlags QgsRasterSymbolLegendNode::flags() const
992 {
993  if ( mCheckable )
994  return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
995  else
996  return Qt::ItemIsEnabled;
997 }
998 
999 QVariant QgsRasterSymbolLegendNode::data( int role ) const
1000 {
1001  switch ( role )
1002  {
1003  case Qt::DecorationRole:
1004  {
1005  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); // TODO: configurable?
1006  QPixmap pix( iconSize, iconSize );
1007  pix.fill( mColor );
1008  return QIcon( pix );
1009  }
1010 
1011  case Qt::DisplayRole:
1012  case Qt::EditRole:
1013  return mUserLabel.isEmpty() ? mLabel : mUserLabel;
1014 
1017 
1019  return mRuleKey;
1020 
1021  case Qt::CheckStateRole:
1022  {
1023  if ( !mCheckable )
1024  return QVariant();
1025 
1026  if ( QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( mLayerNode->layer() ) )
1027  {
1028  if ( !pclayer->renderer() )
1029  return QVariant();
1030 
1031  return pclayer->renderer()->legendItemChecked( mRuleKey ) ? Qt::Checked : Qt::Unchecked;
1032  }
1033 
1034  return QVariant();
1035  }
1036 
1037  default:
1038  return QVariant();
1039  }
1040 }
1041 
1042 bool QgsRasterSymbolLegendNode::setData( const QVariant &value, int role )
1043 {
1044  if ( role != Qt::CheckStateRole )
1045  return false;
1046 
1047  if ( !mCheckable )
1048  return false;
1049 
1050  if ( QgsPointCloudLayer *pclayer = qobject_cast<QgsPointCloudLayer *>( mLayerNode->layer() ) )
1051  {
1052  if ( !pclayer->renderer() )
1053  return false;
1054 
1055  pclayer->renderer()->checkLegendItem( mRuleKey, value == Qt::Checked );
1056 
1057  emit dataChanged();
1058  pclayer->emitStyleChanged();
1059 
1060  pclayer->triggerRepaint();
1061  return true;
1062  }
1063  else
1064  {
1065  return false;
1066  }
1067 }
1068 
1069 
1070 QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
1071 {
1072  QSizeF size = settings.symbolSize();
1073  double offsetX = 0;
1074  if ( ctx )
1075  {
1076  if ( ctx->patchSize.width() > 0 )
1077  {
1078  if ( ctx->patchSize.width() < size.width() )
1079  offsetX = ( size.width() - ctx->patchSize.width() ) / 2.0;
1080  size.setWidth( ctx->patchSize.width() );
1081  }
1082  if ( ctx->patchSize.height() > 0 )
1083  {
1084  size.setHeight( ctx->patchSize.height() );
1085  }
1086  }
1087 
1088  if ( ctx && ctx->painter )
1089  {
1090  QColor itemColor = mColor;
1091  if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
1092  {
1093  if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
1094  itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
1095  }
1096  ctx->painter->setBrush( itemColor );
1097 
1098  if ( settings.drawRasterStroke() )
1099  {
1100  QPen pen;
1101  pen.setColor( settings.rasterStrokeColor() );
1102  pen.setWidthF( settings.rasterStrokeWidth() );
1103  pen.setJoinStyle( Qt::MiterJoin );
1104  ctx->painter->setPen( pen );
1105  }
1106  else
1107  {
1108  ctx->painter->setPen( Qt::NoPen );
1109  }
1110 
1111  switch ( settings.symbolAlignment() )
1112  {
1113  case Qt::AlignLeft:
1114  default:
1115  ctx->painter->drawRect( QRectF( ctx->columnLeft + offsetX, ctx->top + ( itemHeight - size.height() ) / 2,
1116  size.width(), size.height() ) );
1117  break;
1118 
1119  case Qt::AlignRight:
1120  ctx->painter->drawRect( QRectF( ctx->columnRight - size.width() - offsetX, ctx->top + ( itemHeight - size.height() ) / 2,
1121  size.width(), size.height() ) );
1122  break;
1123  }
1124  }
1125  return size;
1126 }
1127 
1129 {
1130  QImage img = QImage( settings.symbolSize().toSize(), QImage::Format_ARGB32 );
1131  img.fill( Qt::transparent );
1132 
1133  QPainter painter( &img );
1134  painter.setRenderHint( QPainter::Antialiasing );
1135 
1136  QColor itemColor = mColor;
1137  if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
1138  {
1139  if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
1140  itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
1141  }
1142  painter.setBrush( itemColor );
1143 
1144  if ( settings.drawRasterStroke() )
1145  {
1146  QPen pen;
1147  pen.setColor( settings.rasterStrokeColor() );
1148  pen.setWidthF( settings.rasterStrokeWidth() );
1149  pen.setJoinStyle( Qt::MiterJoin );
1150  painter.setPen( pen );
1151  }
1152  else
1153  {
1154  painter.setPen( Qt::NoPen );
1155  }
1156 
1157  painter.drawRect( QRectF( 0, 0, settings.symbolSize().width(), settings.symbolSize().height() ) );
1158 
1159  QByteArray byteArray;
1160  QBuffer buffer( &byteArray );
1161  img.save( &buffer, "PNG" );
1162  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
1163 
1164  QJsonObject json;
1165  json[ QStringLiteral( "icon" ) ] = base64;
1166  return json;
1167 }
1168 
1169 // -------------------------------------------------------------------------
1170 
1172  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
1173  , mValid( false )
1174 {
1175 }
1176 
1178 
1179 QImage QgsWmsLegendNode::getLegendGraphic() const
1180 {
1181  if ( ! mValid && ! mFetcher )
1182  {
1183  // or maybe in presence of a downloader we should just delete it
1184  // and start a new one ?
1185 
1186  QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( mLayerNode->layer() );
1187 
1188  if ( layer && layer->isValid() )
1189  {
1190  const QgsLayerTreeModel *mod = model();
1191  if ( ! mod )
1192  return mImage;
1193  const QgsMapSettings *ms = mod->legendFilterMapSettings();
1194 
1195  QgsRasterDataProvider *prov = layer->dataProvider();
1196  if ( ! prov )
1197  return mImage;
1198 
1199  Q_ASSERT( ! mFetcher );
1200  mFetcher.reset( prov->getLegendGraphicFetcher( ms ) );
1201  if ( mFetcher )
1202  {
1203  connect( mFetcher.get(), &QgsImageFetcher::finish, this, &QgsWmsLegendNode::getLegendGraphicFinished );
1204  connect( mFetcher.get(), &QgsImageFetcher::error, this, &QgsWmsLegendNode::getLegendGraphicErrored );
1205  connect( mFetcher.get(), &QgsImageFetcher::progress, this, &QgsWmsLegendNode::getLegendGraphicProgress );
1206  mFetcher->start();
1207  }
1208  }
1209  else
1210  {
1211  QgsDebugMsg( tr( "Failed to download legend graphics: layer is not valid." ) );
1212  }
1213  }
1214 
1215  return mImage;
1216 }
1217 
1218 QVariant QgsWmsLegendNode::data( int role ) const
1219 {
1220  if ( role == Qt::DecorationRole )
1221  {
1222  return QPixmap::fromImage( getLegendGraphic() );
1223  }
1224  else if ( role == Qt::SizeHintRole )
1225  {
1226  return getLegendGraphic().size();
1227  }
1228  else if ( role == QgsLayerTreeModelLegendNode::NodeTypeRole )
1229  {
1231  }
1232  return QVariant();
1233 }
1234 
1235 QSizeF QgsWmsLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
1236 {
1237  Q_UNUSED( itemHeight )
1238 
1239  if ( ctx && ctx->painter )
1240  {
1241  switch ( settings.symbolAlignment() )
1242  {
1243  case Qt::AlignLeft:
1244  default:
1245  ctx->painter->drawImage( QRectF( ctx->columnLeft,
1246  ctx->top,
1247  settings.wmsLegendSize().width(),
1248  settings.wmsLegendSize().height() ),
1249  mImage,
1250  QRectF( QPointF( 0, 0 ), mImage.size() ) );
1251  break;
1252 
1253  case Qt::AlignRight:
1254  ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(),
1255  ctx->top,
1256  settings.wmsLegendSize().width(),
1257  settings.wmsLegendSize().height() ),
1258  mImage,
1259  QRectF( QPointF( 0, 0 ), mImage.size() ) );
1260  break;
1261  }
1262  }
1263  return settings.wmsLegendSize();
1264 }
1265 
1267 {
1268  QByteArray byteArray;
1269  QBuffer buffer( &byteArray );
1270  mImage.save( &buffer, "PNG" );
1271  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
1272 
1273  QJsonObject json;
1274  json[ QStringLiteral( "icon" ) ] = base64;
1275  return json;
1276 }
1277 
1278 QImage QgsWmsLegendNode::renderMessage( const QString &msg ) const
1279 {
1280  const int fontHeight = 10;
1281  const int margin = fontHeight / 2;
1282  const int nlines = 1;
1283 
1284  const int w = 512, h = fontHeight * nlines + margin * ( nlines + 1 );
1285  QImage image( w, h, QImage::Format_ARGB32_Premultiplied );
1286  QPainter painter;
1287  painter.begin( &image );
1288  painter.setPen( QColor( 255, 0, 0 ) );
1289  painter.setFont( QFont( QStringLiteral( "Chicago" ), fontHeight ) );
1290  painter.fillRect( 0, 0, w, h, QColor( 255, 255, 255 ) );
1291  painter.drawText( 0, margin + fontHeight, msg );
1292  //painter.drawText(0,2*(margin+fontHeight),tr("retrying in 5 seconds…"));
1293  painter.end();
1294 
1295  return image;
1296 }
1297 
1298 void QgsWmsLegendNode::getLegendGraphicProgress( qint64 cur, qint64 tot )
1299 {
1300  const QString msg = tot > 0 ? tr( "Downloading: %1% (%2)" ).arg( static_cast< int >( std::round( 100 * cur / tot ) ) ).arg( QgsFileUtils::representFileSize( tot ) )
1301  : tr( "Downloading: %1" ).arg( QgsFileUtils::representFileSize( cur ) );
1302  mImage = renderMessage( msg );
1303  emit dataChanged();
1304 }
1305 
1306 void QgsWmsLegendNode::getLegendGraphicErrored( const QString & )
1307 {
1308  if ( ! mFetcher )
1309  return; // must be coming after finish
1310 
1311  mImage = QImage();
1312  emit dataChanged();
1313 
1314  mFetcher.reset();
1315 
1316  mValid = true; // we consider it valid anyway
1317 }
1318 
1319 void QgsWmsLegendNode::getLegendGraphicFinished( const QImage &image )
1320 {
1321  if ( ! mFetcher )
1322  return; // must be coming after error
1323 
1324  if ( ! image.isNull() )
1325  {
1326  if ( image != mImage )
1327  {
1328  mImage = image;
1329  setUserPatchSize( mImage.size() );
1330  emit dataChanged();
1331  }
1332  mValid = true; // only if not null I guess
1333  }
1334  mFetcher.reset();
1335 }
1336 
1338 {
1339  // TODO: do this only if this extent != prev extent ?
1340  mValid = false;
1341  emit dataChanged();
1342 }
1343 
1344 // -------------------------------------------------------------------------
1345 
1347  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
1348  , mSettings( new QgsDataDefinedSizeLegend( settings ) )
1349 {
1350 }
1351 
1353 {
1354  delete mSettings;
1355 }
1356 
1357 QVariant QgsDataDefinedSizeLegendNode::data( int role ) const
1358 {
1359  if ( role == Qt::DecorationRole )
1360  {
1361  cacheImage();
1362  return QPixmap::fromImage( mImage );
1363  }
1364  else if ( role == Qt::SizeHintRole )
1365  {
1366  cacheImage();
1367  return mImage.size();
1368  }
1369  else if ( role == QgsLayerTreeModelLegendNode::NodeTypeRole )
1370  {
1372  }
1373  return QVariant();
1374 }
1375 
1377 {
1378  // setup temporary render context if none specified
1379  QgsRenderContext *context = nullptr;
1380  std::unique_ptr< QgsRenderContext > tempRenderContext;
1381  if ( ctx && ctx->context )
1382  context = ctx->context;
1383  else
1384  {
1385  tempRenderContext = std::make_unique< QgsRenderContext >();
1386  // QGIS 4.0 - make ItemContext compulsory, so we don't have to construct temporary render contexts here
1388  tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
1389  tempRenderContext->setRendererScale( settings.mapScale() );
1390  tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
1391  tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
1392  tempRenderContext->setForceVectorOutput( true );
1393  tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );
1394  tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
1396 
1397  // setup a minimal expression context
1398  QgsExpressionContext expContext;
1400  tempRenderContext->setExpressionContext( expContext );
1401  context = tempRenderContext.get();
1402  }
1403 
1404  if ( context->painter() )
1405  {
1406  context->painter()->save();
1407  context->painter()->translate( ctx->columnLeft, ctx->top );
1408 
1409  // scale to pixels
1410  context->painter()->scale( 1 / context->scaleFactor(), 1 / context->scaleFactor() );
1411  }
1412 
1413  QgsDataDefinedSizeLegend ddsLegend( *mSettings );
1414  ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
1415  ddsLegend.setTextColor( settings.fontColor() );
1416 
1417  QSizeF contentSize;
1418  double labelXOffset;
1419  ddsLegend.drawCollapsedLegend( *context, &contentSize, &labelXOffset );
1420 
1421  if ( context->painter() )
1422  context->painter()->restore();
1423 
1424  ItemMetrics im;
1425  im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context->scaleFactor(), contentSize.height() / context->scaleFactor() );
1426  im.labelSize = QSizeF( labelXOffset / context->scaleFactor(), contentSize.height() / context->scaleFactor() );
1427  return im;
1428 }
1429 
1430 
1431 void QgsDataDefinedSizeLegendNode::cacheImage() const
1432 {
1433  if ( mImage.isNull() )
1434  {
1435  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
1436  if ( !context )
1437  {
1438  context.reset( new QgsRenderContext );
1439  Q_ASSERT( context ); // to make cppcheck happy
1440  context->setScaleFactor( 96 / 25.4 );
1441  }
1442  mImage = mSettings->collapsedLegendImage( *context );
1443  }
1444 }
1445 
1446 QgsVectorLabelLegendNode::QgsVectorLabelLegendNode( QgsLayerTreeLayer *nodeLayer, const QgsPalLayerSettings &labelSettings, QObject *parent ): QgsLayerTreeModelLegendNode( nodeLayer, parent ), mLabelSettings( labelSettings )
1447 {
1448 }
1449 
1451 {
1452 }
1453 
1454 QVariant QgsVectorLabelLegendNode::data( int role ) const
1455 {
1456  if ( role == Qt::DisplayRole )
1457  {
1458  return mUserLabel;
1459  }
1460  if ( role == Qt::DecorationRole )
1461  {
1462  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
1463  return QgsPalLayerSettings::labelSettingsPreviewPixmap( mLabelSettings, QSize( iconSize, iconSize ), mLabelSettings.legendString() );
1464  }
1465  return QVariant();
1466 }
1467 
1468 QSizeF QgsVectorLabelLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
1469 {
1470  Q_UNUSED( itemHeight );
1471  if ( !ctx )
1472  {
1473  return QSizeF( 0, 0 );
1474  }
1475 
1476  const QgsRenderContext *renderContext = ctx->context;
1477  if ( renderContext )
1478  {
1479  return drawSymbol( settings, *renderContext, ctx->columnLeft, ctx->top );
1480  }
1481 
1482  return QSizeF( 0, 0 );
1483 }
1484 
1485 QSizeF QgsVectorLabelLegendNode::drawSymbol( const QgsLegendSettings &settings, const QgsRenderContext &renderContext, double xOffset, double yOffset ) const
1486 {
1487  QStringList textLines( mLabelSettings.legendString() );
1488  QgsTextFormat textFormat = mLabelSettings.format();
1489  QgsRenderContext ctx( renderContext );
1490  double textWidth, textHeight;
1491  textWidthHeight( textWidth, textHeight, ctx, textFormat, textLines );
1492  textWidth /= renderContext.scaleFactor();
1493  textHeight /= renderContext.scaleFactor();
1494  QPointF textPos( renderContext.scaleFactor() * ( xOffset + settings.symbolSize().width() / 2.0 - textWidth / 2.0 ), renderContext.scaleFactor() * ( yOffset + settings.symbolSize().height() / 2.0 + textHeight / 2.0 ) );
1495 
1496  QgsScopedRenderContextScaleToPixels scopedScaleToPixels( ctx );
1497  QgsTextRenderer::drawText( textPos, 0.0, QgsTextRenderer::AlignLeft, textLines, ctx, textFormat );
1498 
1499  const double symbolWidth = std::max( textWidth, settings.symbolSize().width() );
1500  const double symbolHeight = std::max( textHeight, settings.symbolSize().height() );
1501  return QSizeF( symbolWidth, symbolHeight );
1502 }
1503 
1504 QJsonObject QgsVectorLabelLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context ) const
1505 {
1506  Q_UNUSED( settings );
1507 
1508  const double mmToPixel = 96.0 / 25.4; //settings.dpi() is deprecated
1509 
1510  const QStringList textLines( mLabelSettings.legendString() );
1511  const QgsTextFormat textFormat = mLabelSettings.format();
1512  QgsRenderContext ctx( context );
1513  ctx.setScaleFactor( mmToPixel );
1514 
1515  double textWidth, textHeight;
1516  textWidthHeight( textWidth, textHeight, ctx, textFormat, textLines );
1517  QPixmap previewPixmap = mLabelSettings.labelSettingsPreviewPixmap( mLabelSettings, QSize( textWidth, textHeight ), mLabelSettings.legendString() );
1518 
1519  QByteArray byteArray;
1520  QBuffer buffer( &byteArray );
1521  previewPixmap.save( &buffer, "PNG" );
1522  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
1523 
1524  QJsonObject json;
1525  json[ QStringLiteral( "icon" ) ] = base64;
1526  return json;
1527 }
1528 
1529 void QgsVectorLabelLegendNode::textWidthHeight( double &width, double &height, QgsRenderContext &ctx, const QgsTextFormat &textFormat, const QStringList &textLines ) const
1530 {
1531  QFontMetricsF fm = QgsTextRenderer::fontMetrics( ctx, textFormat );
1532  height = QgsTextRenderer::textHeight( ctx, textFormat, 'A', true );
1533  width = QgsTextRenderer::textWidth( ctx, textFormat, textLines, &fm );
1534 }
1535 
@ Marker
Marker symbol.
@ Line
Line symbol.
QgsDataDefinedSizeLegendNode(QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent=nullptr)
Construct the node using QgsDataDefinedSizeLegend as definition of the node's appearance.
ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx) override
Entry point called from QgsLegendRenderer to do the rendering.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
void setFont(const QFont &font)
Sets font used for rendering of labels - only valid for collapsed legend.
void setTextColor(const QColor &color)
Sets text color for rendering of labels - only valid for collapsed legend.
QImage collapsedLegendImage(QgsRenderContext &context, const QColor &backgroundColor=Qt::transparent, double paddingMM=1) const
Returns output image that would be shown in the legend. Returns invalid image if legend is not config...
void drawCollapsedLegend(QgsRenderContext &context, QSizeF *outputSize SIP_OUT=nullptr, double *labelXOffset SIP_OUT=nullptr) const
Draw the legend if using LegendOneNodeForAll and optionally output size of the legend and x offset of...
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
static QString replaceExpressionText(const QString &action, const QgsExpressionContext *context, const QgsDistanceArea *distanceArea=nullptr)
This function replaces each expression between [% and %] in the string with the result of its evaluat...
virtual void setLegendSymbolItem(const QString &key, QgsSymbol *symbol)
Sets the symbol to be used for a legend symbol item.
virtual void checkLegendSymbolItem(const QString &key, bool state=true)
item in symbology was checked
static QString representFileSize(qint64 bytes)
Returns the human size from bytes.
void progress(qint64 received, qint64 total)
Emitted to report progress.
void error(const QString &msg)
Emitted when an error occurs.
void finish(const QImage &legend)
Emitted when the download completes.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
QgsImageLegendNode(QgsLayerTreeLayer *nodeLayer, const QImage &img, QObject *parent=nullptr)
Constructor for QgsImageLegendNode.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
static QRect nonTransparentImageRect(const QImage &image, QSize minSize=QSize(), bool center=false)
Calculates the non-transparent region of an image.
Layer tree node points to a map layer.
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
QgsLegendPatchShape patchShape() const
Returns the symbol patch shape to use when rendering the legend node symbol.
QString name() const override
Returns the layer's name.
QgsMapLayer * layer() const
Returns the map layer associated with this node.
QSizeF patchSize() const
Returns the user (overridden) size for the legend node.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
virtual QVariant data(int role) const =0
Returns data associated with the item. Must be implemented in derived class.
QJsonObject exportToJson(const QgsLegendSettings &settings, const QgsRenderContext &context)
Entry point called from QgsLegendRenderer to do the rendering in a JSON object.
@ SimpleLegend
Simple label with icon legend node type.
@ RasterSymbolLegend
Raster symbol legend node type.
@ ImageLegend
Raster image legend node type.
@ DataDefinedSizeLegend
Marker symbol legend node type.
@ SymbolLegend
Vector symbol legend node type.
void checkAllItems()
Checks all checkable items belonging to the same layer as this node.
void uncheckAllItems()
Unchecks all checkable items belonging to the same layer as this node.
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
QgsLayerTreeModelLegendNode(QgsLayerTreeLayer *nodeL, QObject *parent=nullptr)
Construct the node with pointer to its parent layer node.
virtual void setUserPatchSize(QSizeF size)
Sets the user (overridden) size for the legend node.
@ ParentRuleKeyRole
Rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2....
@ RuleKeyRole
Rule key of the node (QString)
@ NodeTypeRole
Type of node. Added in 3.16.
void sizeChanged()
Emitted when the size of this node changes.
void dataChanged()
Emitted on internal data change so the layer tree model can forward the signal to views.
QgsRenderContext * createTemporaryRenderContext() const
Returns a temporary context or nullptr if legendMapViewData are not valid.
virtual QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const
Adds a symbol in base64 string within a JSON object with the key "icon".
QgsLayerTreeModel * model() const
Returns pointer to model owning this legend node.
void toggleAllItems()
Toggle all checkable items belonging to the same layer as this node.
virtual QSizeF userPatchSize() const
Returns the user (overridden) size for the legend node.
virtual ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx)
Entry point called from QgsLegendRenderer to do the rendering.
virtual Qt::ItemFlags flags() const
Returns item flags associated with the item. Default implementation returns Qt::ItemIsEnabled.
virtual QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const
Draws symbol on the left side of the item.
virtual void setEmbeddedInParent(bool embedded)
virtual bool setData(const QVariant &value, int role)
Sets some data associated with the item. Default implementation does nothing and returns false.
virtual QSizeF drawSymbolText(const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize) const
Draws label on the right side of the item.
The QgsLayerTreeModel class is model implementation for Qt item views framework.
const QgsMapSettings * legendFilterMapSettings() const
Returns the current map settings used for the current legend filter (or nullptr if none is enabled)
static int scaleIconSize(int standardSize)
Scales an layer tree model icon size to compensate for display pixel density, making the icon size hi...
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.
Represents a patch shape for use in map legends.
The QgsLegendSettings class stores the appearance and layout settings for legend drawing with QgsLege...
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns the style for a legend component.
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
QSizeF wmsLegendSize() const
Returns the size (in millimeters) of WMS legend graphics shown in the legend.
double minimumSymbolSize() const
Returns the minimum symbol size (in mm).
double rasterStrokeWidth() const
Returns the stroke width (in millimeters) for the stroke drawn around raster symbol items.
double fontDescentMillimeters(const QFont &font) const
Returns the font descent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCA...
QSizeF symbolSize() const
Returns the default symbol size (in millimeters) used for legend items.
QColor fontColor() const
Returns the font color used for legend items.
double maximumSymbolSize() const
Returns the maximum symbol size (in mm).
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
Q_DECL_DEPRECATED bool useAdvancedEffects() const
double fontHeightCharacterMM(const QFont &font, QChar c) const
Returns the font height of a character in millimeters.
Q_DECL_DEPRECATED int dpi() const
double lineSpacing() const
Returns the line spacing to use between lines of legend text.
Q_DECL_DEPRECATED double mmPerMapUnit() const
QStringList evaluateItemText(const QString &text, const QgsExpressionContext &context) const
Splits a string using the wrap char taking into account handling empty wrap char which means no wrapp...
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
Q_DECL_DEPRECATED double mapScale() const
Returns the legend map scale.
double margin(Side side)
Returns the margin (in mm) for the specified side of the component.
Qt::Alignment alignment() const
Returns the alignment for the legend component.
QFont font() const
Returns the font used for rendering this legend component.
@ Right
Right side.
@ Left
Left side.
@ Symbol
Symbol icon (excluding label)
@ SymbolLabel
Symbol label (excluding icon)
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
QString parentRuleKey() const
Key of the parent legend node.
int scaleMaxDenom() const
Max scale denominator of the scale range.
void setSymbol(QgsSymbol *s)
Sets the symbol of the item.
QgsSymbol * symbol() const
Returns associated symbol. May be nullptr.
int scaleMinDenom() const
Min scale denominator of the scale range.
QString ruleKey() const
Returns unique identifier of the rule for identification of the item within renderer.
bool isCheckable() const
Returns whether the item is user-checkable - whether renderer supports enabling/disabling it.
QString label() const
Returns text label.
Base class for all map layer types.
Definition: qgsmaplayer.h:70
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
bool isValid
Definition: qgsmaplayer.h:78
The QgsMapSettings class contains configuration for rendering of the map.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:39
A marker symbol type, for rendering Point and MultiPoint geometries.
Contains settings for how a map layer will be labeled.
QString legendString() const
legendString
static QPixmap labelSettingsPreviewPixmap(const QgsPalLayerSettings &settings, QSize size, const QString &previewText=QString(), int padding=0)
Returns a pixmap preview for label settings.
const QgsTextFormat & format() const
Returns the label text formatting settings, e.g., font settings, buffer settings, etc.
Represents a map layer supporting display of point clouds.
Base class for raster data providers.
virtual QgsImageFetcher * getLegendGraphicFetcher(const QgsMapSettings *mapSettings)
Returns a new image downloader for the raster legend.
Represents a raster layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Raster renderer pipe that applies colors to a raster.
Qt::ItemFlags flags() const override
Returns item flags associated with the item. Default implementation returns Qt::ItemIsEnabled.
bool setData(const QVariant &value, int role) override
Sets some data associated with the item. Default implementation does nothing and returns false.
QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
QgsRasterSymbolLegendNode(QgsLayerTreeLayer *nodeLayer, const QColor &color, const QString &label, QObject *parent=nullptr, bool isCheckable=false, const QString &ruleKey=QString())
Constructor for QgsRasterSymbolLegendNode.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
Contains information about the context of a rendering operation.
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
QPainter * painter()
Returns the destination QPainter for the render operation.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setPainterFlagsUsingContext(QPainter *painter=nullptr) const
Sets relevant flags on a destination painter, using the flags and settings currently defined for the ...
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context's map to pixel transform, which transforms between map coordinates and device coordi...
@ Antialiasing
Use antialiasing while drawing.
@ RenderSymbolPreview
The render is for a symbol preview only and map based properties may not be available,...
@ UseAdvancedEffects
Enable layer opacity and blending effects.
@ LosslessImageRendering
Render images losslessly whenever possible, instead of the default lossy jpeg rendering used for some...
Flags flags() const
Returns combination of flags used for rendering.
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setRendererScale(double scale)
Sets the renderer map scale.
Scoped object for saving and restoring a QPainter object's state.
Scoped object for temporary scaling of a QgsRenderContext for pixel based rendering.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
QgsSimpleLegendNode(QgsLayerTreeLayer *nodeLayer, const QString &label, const QIcon &icon=QIcon(), QObject *parent=nullptr, const QString &key=QString())
Constructor for QgsSimpleLegendNode.
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr)
Returns a pixmap preview for a color ramp.
static QgsSymbol * restrictedSizeSymbol(const QgsSymbol *s, double minSize, double maxSize, QgsRenderContext *context, double &width, double &height)
Creates a new symbol with size restricted to min/max size if original size is out of min/max range.
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
QString evaluateLabel(const QgsExpressionContext &context=QgsExpressionContext(), const QString &label=QString())
Evaluates and returns the text label of the current node.
const QgsSymbol * symbol() const
Returns the symbol used by the legend node.
void setPatchShape(const QgsLegendPatchShape &shape)
Sets the symbol patch shape to use when rendering the legend node symbol.
QgsSymbolLegendNode(QgsLayerTreeLayer *nodeLayer, const QgsLegendSymbolItem &item, QObject *parent=nullptr)
Constructor for QgsSymbolLegendNode.
QgsLegendPatchShape patchShape() const
Returns the symbol patch shape to use when rendering the legend node symbol.
QSize minimumIconSize() const
Calculates the minimum icon size to prevent cropping.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
void invalidateMapBasedData() override
Notification from model that information from associated map view has changed.
bool setData(const QVariant &value, int role) override
Sets some data associated with the item. Default implementation does nothing and returns false.
Qt::ItemFlags flags() const override
Returns item flags associated with the item. Default implementation returns Qt::ItemIsEnabled.
void setCustomSymbol(QgsSymbol *symbol)
Sets the node's custom symbol.
void setEmbeddedInParent(bool embedded) override
QgsSymbol * customSymbol() const
Returns the node's custom symbol.
QString symbolLabel() const
Label of the symbol, user defined label will be used, otherwise will default to the label made by QGI...
void setSymbol(QgsSymbol *symbol)
Sets the symbol to be used by the legend node.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:38
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *patchShape=nullptr)
Draws an icon of the symbol that occupies an area given by size using the specified painter.
Definition: qgssymbol.cpp:562
bool usesMapUnits() const
Returns true if the symbol has any components which use map unit based sizes.
Definition: qgssymbol.cpp:296
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:97
Container for all settings relating to text rendering.
Definition: qgstextformat.h:41
QFont scaledFont(const QgsRenderContext &context, double scaleFactor=1.0) const
Returns a font with the size scaled to match the format's size settings (including units and map unit...
static double textWidth(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, QFontMetricsF *fontMetrics=nullptr)
Returns the width of a text based on a given format.
@ AlignLeft
Left align.
@ AlignCenter
Center align.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode=Point, QFontMetricsF *fontMetrics=nullptr)
Returns the height of a text based on a given format.
static QFontMetricsF fontMetrics(QgsRenderContext &context, const QgsTextFormat &format, double scaleFactor=1.0)
Returns the font metrics for the given text format, when rendered in the specified render context.
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true, VAlignment vAlignment=AlignTop)
Draws text within a rectangle using the specified settings.
@ Point
Text at point of origin draw mode.
QgsVectorLabelLegendNode(QgsLayerTreeLayer *nodeLayer, const QgsPalLayerSettings &labelSettings, QObject *parent=nullptr)
QgsVectorLabelLegendNode.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
drawSymbol
QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const override
exportSymbolToJson
QVariant data(int role) const override
data Returns data associated with the item
Represents a vector layer which manages a vector based data sets.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
void invalidateMapBasedData() override
Notification from model that information from associated map view has changed.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
~QgsWmsLegendNode() override
QgsWmsLegendNode(QgsLayerTreeLayer *nodeLayer, QObject *parent=nullptr)
Constructor for QgsWmsLegendNode.
QJsonObject exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:1080
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:1079
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:598
QList< QgsLegendSymbolItem > QgsLegendSymbolList
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Single variable definition for use within a QgsExpressionContextScope.
double top
Top y-position of legend item.
QgsLegendPatchShape patchShape
The patch shape to render for the node.
double maxSiblingSymbolWidth
Largest symbol width, considering all other sibling legend components associated with the current com...
QSizeF patchSize
Symbol patch size to render for the node.
double columnLeft
Left side of current legend column.
double columnRight
Right side of current legend column.
Q_NOWARN_DEPRECATED_POP QgsRenderContext * context
Render context, if available.