QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
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 "qgsrasterrenderer.h"
32 #include "qgsfeatureid.h"
33 #include "qgslayoutitem.h"
35 #include "qgsexpression.h"
36 
37 
39  : QObject( parent )
40  , mLayerNode( nodeL )
41  , mEmbeddedInParent( false )
42 {
43 }
44 
46 {
47  return qobject_cast<QgsLayerTreeModel *>( parent() );
48 }
49 
51 {
52  return Qt::ItemIsEnabled;
53 }
54 
55 bool QgsLayerTreeModelLegendNode::setData( const QVariant &value, int role )
56 {
57  Q_UNUSED( value )
58  Q_UNUSED( role )
59  return false;
60 }
61 
62 
64 {
65  QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
66 
67  double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
68  // itemHeight here is not really item height, it is only for symbol
69  // vertical alignment purpose, i.e. OK take single line height
70  // if there are more lines, thos run under the symbol
71  double itemHeight = std::max( static_cast< double >( settings.symbolSize().height() ), textHeight );
72 
73  ItemMetrics im;
74  im.symbolSize = drawSymbol( settings, ctx, itemHeight );
75  im.labelSize = drawSymbolText( settings, ctx, im.symbolSize );
76  return im;
77 }
78 
79 void QgsLayerTreeModelLegendNode::exportToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json )
80 {
81  exportSymbolToJson( settings, context, json );
82  exportSymbolTextToJson( settings, json );
83 }
84 
85 QSizeF QgsLayerTreeModelLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
86 {
87  QIcon symbolIcon = data( Qt::DecorationRole ).value<QIcon>();
88  if ( symbolIcon.isNull() )
89  return QSizeF();
90 
91  if ( ctx && ctx->painter )
92  {
93  switch ( settings.symbolAlignment() )
94  {
95  case Qt::AlignLeft:
96  default:
97  symbolIcon.paint( ctx->painter,
98  static_cast< int >( ctx->columnLeft ),
99  static_cast< int >( ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2 ),
100  static_cast< int >( settings.symbolSize().width() ),
101  static_cast< int >( settings.symbolSize().height() ) );
102  break;
103 
104  case Qt::AlignRight:
105  symbolIcon.paint( ctx->painter,
106  static_cast< int >( ctx->columnRight - settings.symbolSize().width() ),
107  static_cast< int >( ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2 ),
108  static_cast< int >( settings.symbolSize().width() ),
109  static_cast< int >( settings.symbolSize().height() ) );
110  break;
111  }
112  }
113  return settings.symbolSize();
114 }
115 
116 void QgsLayerTreeModelLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
117 {
118  const QIcon icon = data( Qt::DecorationRole ).value<QIcon>();
119  if ( icon.isNull() )
120  return;
121 
122  const QImage image( icon.pixmap( settings.symbolSize().width(), settings.symbolSize().height() ).toImage() );
123  QByteArray byteArray;
124  QBuffer buffer( &byteArray );
125  image.save( &buffer, "PNG" );
126  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
127  json[ "icon" ] = base64;
128 }
129 
130 QSizeF QgsLayerTreeModelLegendNode::drawSymbolText( const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize ) const
131 {
132  QSizeF labelSize( 0, 0 );
133 
134  QFont symbolLabelFont = settings.style( QgsLegendStyle::SymbolLabel ).font();
135  double textHeight = settings.fontHeightCharacterMM( symbolLabelFont, QChar( '0' ) );
136  double textDescent = settings.fontDescentMillimeters( symbolLabelFont );
137 
138  QgsExpressionContext tempContext;
139 
140  const QStringList lines = settings.evaluateItemText( data( Qt::DisplayRole ).toString(), ctx && ctx->context ? ctx->context->expressionContext() : tempContext );
141 
142  labelSize.rheight() = lines.count() * textHeight + ( lines.count() - 1 ) * ( settings.lineSpacing() + textDescent );
143 
144  double labelXMin = 0.0;
145  double labelXMax = 0.0;
146  double labelY = 0.0;
147  if ( ctx && ctx->painter )
148  {
149  ctx->painter->setPen( settings.fontColor() );
150  switch ( settings.symbolAlignment() )
151  {
152  case Qt::AlignLeft:
153  default:
154  labelXMin = ctx->columnLeft + std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
157  labelXMax = ctx->columnRight;
158  break;
159 
160  case Qt::AlignRight:
161  labelXMin = ctx->columnLeft;
162  // NOTE -- while the below calculations use the flipped margins from the style, that's only done because
163  // those are the only margins we expose and use for now! (and we expose them as generic margins, not side-specific
164  // ones) TODO when/if we expose other margin settings, these should be reversed...
165  labelXMax = ctx->columnRight - std::max( static_cast< double >( symbolSize.width() ), ctx->maxSiblingSymbolWidth )
168  break;
169  }
170 
171  labelY = ctx->top;
172 
173  // Vertical alignment of label with symbol
174  if ( labelSize.height() < symbolSize.height() )
175  labelY += symbolSize.height() / 2 - labelSize.height() / 2; // label centered with symbol
176 
177  labelY += textHeight;
178  }
179 
180  for ( QStringList::ConstIterator itemPart = lines.constBegin(); itemPart != lines.constEnd(); ++itemPart )
181  {
182  const double lineWidth = settings.textWidthMillimeters( symbolLabelFont, *itemPart );
183  labelSize.rwidth() = std::max( lineWidth, double( labelSize.width() ) );
184 
185  if ( ctx && ctx->painter )
186  {
187  switch ( settings.style( QgsLegendStyle::SymbolLabel ).alignment() )
188  {
189  case Qt::AlignLeft:
190  default:
191  settings.drawText( ctx->painter, labelXMin, labelY, *itemPart, symbolLabelFont );
192  break;
193 
194  case Qt::AlignRight:
195  settings.drawText( ctx->painter, labelXMax - lineWidth, labelY, *itemPart, symbolLabelFont );
196  break;
197 
198  case Qt::AlignHCenter:
199  settings.drawText( ctx->painter, labelXMin + ( labelXMax - labelXMin - lineWidth ) / 2.0, labelY, *itemPart, symbolLabelFont );
200  break;
201  }
202 
203  if ( itemPart != ( lines.end() - 1 ) )
204  labelY += textDescent + settings.lineSpacing() + textHeight;
205  }
206  }
207 
208  return labelSize;
209 }
210 
212 {
213  const QString text = data( Qt::DisplayRole ).toString();
214  json[ "title" ] = text;
215 }
216 
217 // -------------------------------------------------------------------------
218 
220  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
221  , mItem( item )
222  , mSymbolUsesMapUnits( false )
223 {
224  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
225  mIconSize = QSize( iconSize, iconSize );
226 
227  updateLabel();
228  connect( qobject_cast<QgsVectorLayer *>( nodeLayer->layer() ), &QgsVectorLayer::symbolFeatureCountMapChanged, this, &QgsSymbolLegendNode::updateLabel );
229  connect( nodeLayer, &QObject::destroyed, this, [ = ]() { mLayerNode = nullptr; } );
230 
231  if ( mItem.symbol() )
232  mSymbolUsesMapUnits = ( mItem.symbol()->outputUnit() != QgsUnitTypes::RenderMillimeters );
233 }
234 
235 Qt::ItemFlags QgsSymbolLegendNode::flags() const
236 {
237  if ( mItem.isCheckable() )
238  return Qt::ItemIsEnabled | Qt::ItemIsUserCheckable;
239  else
240  return Qt::ItemIsEnabled;
241 }
242 
243 
245 {
246  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
247  return minimumIconSize( context.get() );
248 }
249 
251 {
252  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 );
253  const int largeIconSize = QgsLayerTreeModel::scaleIconSize( 512 );
254  QSize minSz( iconSize, iconSize );
255  if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Marker )
256  {
258  QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( largeIconSize, largeIconSize ), 0,
259  context ).toImage(),
260  minSz,
261  true ).size();
262  }
263  else if ( mItem.symbol() && mItem.symbol()->type() == QgsSymbol::Line )
264  {
266  QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), QSize( minSz.width(), largeIconSize ), 0,
267  context ).toImage(),
268  minSz,
269  true ).size();
270  }
271 
272  if ( !mTextOnSymbolLabel.isEmpty() && context )
273  {
274  double w = QgsTextRenderer::textWidth( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel );
275  double h = QgsTextRenderer::textHeight( *context, mTextOnSymbolTextFormat, QStringList() << mTextOnSymbolLabel, QgsTextRenderer::Point );
276  int wInt = ceil( w ), hInt = ceil( h );
277  if ( wInt > minSz.width() ) minSz.setWidth( wInt );
278  if ( hInt > minSz.height() ) minSz.setHeight( hInt );
279  }
280 
281  if ( mItem.level() != 0 && !( model() && model()->testFlag( QgsLayerTreeModel::ShowLegendAsTree ) ) )
282  minSz.setWidth( mItem.level() * INDENT_SIZE + minSz.width() );
283 
284  return minSz;
285 }
286 
288 {
289  return mItem.symbol();
290 }
291 
293 {
294  QString label;
295  if ( mEmbeddedInParent )
296  {
297  QVariant legendlabel = mLayerNode->customProperty( QStringLiteral( "legend/title-label" ) );
298  QString layerName = legendlabel.isNull() ? mLayerNode->name() : legendlabel.toString();
299  label = mUserLabel.isEmpty() ? layerName : mUserLabel;
300  }
301  else
302  label = mUserLabel.isEmpty() ? mItem.label() : mUserLabel;
303  return label;
304 }
305 
307 {
308  if ( !symbol )
309  return;
310 
311  std::unique_ptr< QgsSymbol > s( symbol ); // this method takes ownership of symbol
312  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
313  if ( !vlayer || !vlayer->renderer() )
314  return;
315 
316  mItem.setSymbol( s.get() ); // doesn't transfer ownership
317  vlayer->renderer()->setLegendSymbolItem( mItem.ruleKey(), s.release() ); // DOES transfer ownership!
318 
319  mPixmap = QPixmap();
320 
321  emit dataChanged();
322  vlayer->triggerRepaint();
323 }
324 
326 {
327  checkAll( true );
328 }
329 
331 {
332  checkAll( false );
333 }
334 
336 {
337  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
338  if ( !vlayer || !vlayer->renderer() )
339  return;
340 
341  const QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems();
342  for ( const auto &item : symbolList )
343  {
344  vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), ! vlayer->renderer()->legendSymbolItemChecked( item.ruleKey() ) );
345  }
346 
347  emit dataChanged();
348  vlayer->triggerRepaint();
349 }
350 
352 {
353  double scale = 0.0;
354  double mupp = 0.0;
355  int dpi = 0;
356  if ( model() )
357  model()->legendMapViewData( &mupp, &dpi, &scale );
358 
359  if ( qgsDoubleNear( mupp, 0.0 ) || dpi == 0 || qgsDoubleNear( scale, 0.0 ) )
360  return nullptr;
361 
362  // setup temporary render context
363  std::unique_ptr<QgsRenderContext> context = qgis::make_unique<QgsRenderContext>( );
364  context->setScaleFactor( dpi / 25.4 );
365  context->setRendererScale( scale );
366  context->setMapToPixel( QgsMapToPixel( mupp ) );
367  return context.release();
368 }
369 
370 void QgsSymbolLegendNode::checkAll( bool state )
371 {
372  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
373  if ( !vlayer || !vlayer->renderer() )
374  return;
375 
376  const QgsLegendSymbolList symbolList = vlayer->renderer()->legendSymbolItems();
377  for ( const auto &item : symbolList )
378  {
379  vlayer->renderer()->checkLegendSymbolItem( item.ruleKey(), state );
380  }
381 
382  emit dataChanged();
383  vlayer->triggerRepaint();
384 }
385 
386 QVariant QgsSymbolLegendNode::data( int role ) const
387 {
388  if ( role == Qt::DisplayRole )
389  {
390  return mLabel;
391  }
392  else if ( role == Qt::EditRole )
393  {
394  return mUserLabel.isEmpty() ? mItem.label() : mUserLabel;
395  }
396  else if ( role == Qt::DecorationRole )
397  {
398  if ( mPixmap.isNull() || mPixmap.size() != mIconSize )
399  {
400  QPixmap pix;
401  if ( mItem.symbol() )
402  {
403  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
404  pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), mIconSize, 0, context.get() );
405 
406  if ( !mTextOnSymbolLabel.isEmpty() && context )
407  {
408  QPainter painter( &pix );
409  painter.setRenderHint( QPainter::Antialiasing );
410  context->setPainter( &painter );
411  QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context ) );
412  qreal yBaselineVCenter = ( mIconSize.height() + fm.ascent() - fm.descent() ) / 2;
413  QgsTextRenderer::drawText( QPointF( mIconSize.width() / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
414  QStringList() << mTextOnSymbolLabel, *context, mTextOnSymbolTextFormat );
415  }
416  }
417  else
418  {
419  pix = QPixmap( mIconSize );
420  pix.fill( Qt::transparent );
421  }
422 
423  if ( mItem.level() == 0 || ( model() && model()->testFlag( QgsLayerTreeModel::ShowLegendAsTree ) ) )
424  mPixmap = pix;
425  else
426  {
427  // ident the symbol icon to make it look like a tree structure
428  QPixmap pix2( pix.width() + mItem.level() * INDENT_SIZE, pix.height() );
429  pix2.fill( Qt::transparent );
430  QPainter p( &pix2 );
431  p.drawPixmap( mItem.level() * INDENT_SIZE, 0, pix );
432  p.end();
433  mPixmap = pix2;
434  }
435  }
436  return mPixmap;
437  }
438  else if ( role == Qt::CheckStateRole )
439  {
440  if ( !mItem.isCheckable() )
441  return QVariant();
442 
443  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
444  if ( !vlayer || !vlayer->renderer() )
445  return QVariant();
446 
447  return vlayer->renderer()->legendSymbolItemChecked( mItem.ruleKey() ) ? Qt::Checked : Qt::Unchecked;
448  }
449  else if ( role == RuleKeyRole )
450  {
451  return mItem.ruleKey();
452  }
453  else if ( role == ParentRuleKeyRole )
454  {
455  return mItem.parentRuleKey();
456  }
457 
458  return QVariant();
459 }
460 
461 bool QgsSymbolLegendNode::setData( const QVariant &value, int role )
462 {
463  if ( role != Qt::CheckStateRole )
464  return false;
465 
466  if ( !mItem.isCheckable() )
467  return false;
468 
469  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
470  if ( !vlayer || !vlayer->renderer() )
471  return false;
472 
473  vlayer->renderer()->checkLegendSymbolItem( mItem.ruleKey(), value == Qt::Checked );
474 
475  emit dataChanged();
476  vlayer->emitStyleChanged();
477 
478  vlayer->triggerRepaint();
479 
480  return true;
481 }
482 
483 
484 
485 QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
486 {
487  QgsSymbol *s = mItem.symbol();
488  if ( !s )
489  {
490  return QSizeF();
491  }
492 
493  // setup temporary render context
494  QgsRenderContext *context = nullptr;
495  std::unique_ptr< QgsRenderContext > tempRenderContext;
496  if ( ctx && ctx->context )
497  context = ctx->context;
498  else
499  {
500  tempRenderContext = qgis::make_unique< QgsRenderContext >();
501  tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
502  tempRenderContext->setRendererScale( settings.mapScale() );
503  tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
504  tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
505  tempRenderContext->setForceVectorOutput( true );
506  tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );
507 
508  // setup a minimal expression context
509  QgsExpressionContext expContext;
511  tempRenderContext->setExpressionContext( expContext );
512  context = tempRenderContext.get();
513  }
514 
515  //Consider symbol size for point markers
516  double height = settings.symbolSize().height();
517  double width = settings.symbolSize().width();
518 
519  //Center small marker symbols
520  double widthOffset = 0;
521  double heightOffset = 0;
522 
523  if ( QgsMarkerSymbol *markerSymbol = dynamic_cast<QgsMarkerSymbol *>( s ) )
524  {
525  // allow marker symbol to occupy bigger area if necessary
526  double size = markerSymbol->size( *context ) / context->scaleFactor();
527  height = size;
528  width = size;
529  if ( width < settings.symbolSize().width() )
530  {
531  widthOffset = ( settings.symbolSize().width() - width ) / 2.0;
532  }
533  if ( height < settings.symbolSize().height() )
534  {
535  heightOffset = ( settings.symbolSize().height() - height ) / 2.0;
536  }
537  }
538 
539  if ( ctx && ctx->painter )
540  {
541  double currentYCoord = ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2;
542  QPainter *p = ctx->painter;
543 
544  //setup painter scaling to dots so that raster symbology is drawn to scale
545  double dotsPerMM = context->scaleFactor();
546 
547  int opacity = 255;
548  if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
549  opacity = static_cast<int >( std::round( 255 * vectorLayer->opacity() ) );
550 
551  p->save();
552  p->setRenderHint( QPainter::Antialiasing );
553 
554  switch ( settings.symbolAlignment() )
555  {
556  case Qt::AlignLeft:
557  default:
558  p->translate( ctx->columnLeft + widthOffset, currentYCoord + heightOffset );
559  break;
560  case Qt::AlignRight:
561  p->translate( ctx->columnRight - widthOffset - width, currentYCoord + heightOffset );
562  break;
563  }
564 
565  p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
566  if ( opacity != 255 && settings.useAdvancedEffects() )
567  {
568  const int maxBleed = static_cast< int >( std::ceil( QgsSymbolLayerUtils::estimateMaxSymbolBleed( s, *context ) ) );
569 
570  //semi transparent layer, so need to draw symbol to an image (to flatten it first)
571  //create image which is same size as legend rect, in case symbol bleeds outside its alloted space
572  const QSize symbolSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast<int >( std::round( height * dotsPerMM ) ) );
573  const QSize tempImageSize( symbolSize.width() + maxBleed * 2, symbolSize.height() + maxBleed * 2 );
574  QImage tempImage = QImage( tempImageSize, QImage::Format_ARGB32 );
575  tempImage.fill( Qt::transparent );
576  QPainter imagePainter( &tempImage );
577  imagePainter.setRenderHint( QPainter::Antialiasing );
578  context->setPainter( &imagePainter );
579  imagePainter.translate( maxBleed, maxBleed );
580  s->drawPreviewIcon( &imagePainter, symbolSize, context );
581  imagePainter.translate( -maxBleed, -maxBleed );
582  context->setPainter( ctx->painter );
583  //reduce opacity of image
584  imagePainter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
585  imagePainter.fillRect( tempImage.rect(), QColor( 0, 0, 0, opacity ) );
586  imagePainter.end();
587  //draw rendered symbol image
588  p->drawImage( -maxBleed, -maxBleed, tempImage );
589  }
590  else
591  {
592  s->drawPreviewIcon( p, QSize( static_cast< int >( std::round( width * dotsPerMM ) ), static_cast< int >( std::round( height * dotsPerMM ) ) ), context );
593  }
594 
595  if ( !mTextOnSymbolLabel.isEmpty() )
596  {
597  QFontMetricsF fm( mTextOnSymbolTextFormat.scaledFont( *context ) );
598  qreal yBaselineVCenter = ( height * dotsPerMM + fm.ascent() - fm.descent() ) / 2;
599  QgsTextRenderer::drawText( QPointF( width * dotsPerMM / 2, yBaselineVCenter ), 0, QgsTextRenderer::AlignCenter,
600  QStringList() << mTextOnSymbolLabel, *context, mTextOnSymbolTextFormat );
601  }
602 
603  p->restore();
604  }
605 
606  return QSizeF( std::max( width + 2 * widthOffset, static_cast< double >( settings.symbolSize().width() ) ),
607  std::max( height + 2 * heightOffset, static_cast< double >( settings.symbolSize().height() ) ) );
608 }
609 
610 void QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json ) const
611 {
612  const QgsSymbol *s = mItem.symbol();
613  if ( !s )
614  {
615  return;
616  }
617 
618  QgsRenderContext ctx;
619  ctx.setScaleFactor( settings.dpi() / 25.4 );
620  ctx.setRendererScale( settings.mapScale() );
621  ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
622  ctx.setForceVectorOutput( true );
623 
624  // ensure that a minimal expression context is available
625  QgsExpressionContext expContext = context.expressionContext();
627  ctx.setExpressionContext( expContext );
628 
629  const QPixmap pix = QgsSymbolLayerUtils::symbolPreviewPixmap( mItem.symbol(), minimumIconSize(), 0, &ctx );
630  QImage img( pix.toImage().convertToFormat( QImage::Format_ARGB32_Premultiplied ) );
631 
632  int opacity = 255;
633  if ( QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( layerNode()->layer() ) )
634  opacity = ( 255 * vectorLayer->opacity() );
635 
636  if ( opacity != 255 )
637  {
638  QPainter painter;
639  painter.begin( &img );
640  painter.setCompositionMode( QPainter::CompositionMode_DestinationIn );
641  painter.fillRect( pix.rect(), QColor( 0, 0, 0, opacity ) );
642  painter.end();
643  }
644 
645  QByteArray byteArray;
646  QBuffer buffer( &byteArray );
647  img.save( &buffer, "PNG" );
648  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
649  json[ "icon" ] = base64;
650 }
651 
653 {
655  updateLabel();
656 }
657 
658 
660 {
661  if ( mSymbolUsesMapUnits )
662  {
663  mPixmap = QPixmap();
664  emit dataChanged();
665  }
666 }
667 
668 
669 void QgsSymbolLegendNode::updateLabel()
670 {
671  if ( !mLayerNode )
672  return;
673 
674  bool showFeatureCount = mLayerNode->customProperty( QStringLiteral( "showFeatureCount" ), 0 ).toBool();
675  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
676  mLabel = symbolLabel();
677 
678  if ( showFeatureCount && vl )
679  {
680  qlonglong count = mEmbeddedInParent ? vl->featureCount() : vl->featureCount( mItem.ruleKey() ) ;
681  mLabel += QStringLiteral( " [%1]" ).arg( count != -1 ? QLocale().toString( count ) : tr( "N/A" ) );
682  }
683 
684  emit dataChanged();
685 }
686 
687 QString QgsSymbolLegendNode::evaluateLabel( const QgsExpressionContext &context, const QString &label )
688 {
689  if ( !mLayerNode )
690  return QString();
691 
692  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
693 
694  if ( vl )
695  {
696  QgsExpressionContext contextCopy = QgsExpressionContext( context );
697  QgsExpressionContextScope *symbolScope = createSymbolScope();
698  contextCopy.appendScope( symbolScope );
699  contextCopy.appendScope( vl->createExpressionContextScope() );
700 
701  if ( label.isEmpty() )
702  {
703  if ( ! mLayerNode->labelExpression().isEmpty() )
704  mLabel = QgsExpression::replaceExpressionText( "[%" + mLayerNode->labelExpression() + "%]", &contextCopy );
705  else if ( mLabel.contains( "[%" ) )
706  {
707  const QString symLabel = symbolLabel();
708  mLabel = QgsExpression::replaceExpressionText( symLabel, &contextCopy );
709  }
710  return mLabel;
711  }
712  else
713  {
714  QString eLabel;
715  if ( ! mLayerNode->labelExpression().isEmpty() )
716  eLabel = QgsExpression::replaceExpressionText( label + "[%" + mLayerNode->labelExpression() + "%]", &contextCopy );
717  else if ( label.contains( "[%" ) )
718  eLabel = QgsExpression::replaceExpressionText( label, &contextCopy );
719  return eLabel;
720  }
721  }
722  return mLabel;
723 }
724 
725 QgsExpressionContextScope *QgsSymbolLegendNode::createSymbolScope() const
726 {
727  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mLayerNode->layer() );
728 
729  QgsExpressionContextScope *scope = new QgsExpressionContextScope( tr( "Symbol scope" ) );
730  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_label" ), symbolLabel().remove( "[%" ).remove( "%]" ), true ) );
731  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_id" ), mItem.ruleKey(), true ) );
732  if ( vl )
733  {
734  scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "symbol_count" ), QVariant::fromValue( vl->featureCount( mItem.ruleKey() ) ), true ) );
735  }
736  return scope;
737 }
738 
739 // -------------------------------------------------------------------------
740 
741 
742 QgsSimpleLegendNode::QgsSimpleLegendNode( QgsLayerTreeLayer *nodeLayer, const QString &label, const QIcon &icon, QObject *parent, const QString &key )
743  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
744  , mLabel( label )
745  , mIcon( icon )
746  , mKey( key )
747 {
748 }
749 
750 QVariant QgsSimpleLegendNode::data( int role ) const
751 {
752  if ( role == Qt::DisplayRole || role == Qt::EditRole )
753  return mUserLabel.isEmpty() ? mLabel : mUserLabel;
754  else if ( role == Qt::DecorationRole )
755  return mIcon;
756  else if ( role == RuleKeyRole && !mKey.isEmpty() )
757  return mKey;
758  else
759  return QVariant();
760 }
761 
762 
763 // -------------------------------------------------------------------------
764 
765 QgsImageLegendNode::QgsImageLegendNode( QgsLayerTreeLayer *nodeLayer, const QImage &img, QObject *parent )
766  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
767  , mImage( img )
768 {
769 }
770 
771 QVariant QgsImageLegendNode::data( int role ) const
772 {
773  if ( role == Qt::DecorationRole )
774  {
775  return QPixmap::fromImage( mImage );
776  }
777  else if ( role == Qt::SizeHintRole )
778  {
779  return mImage.size();
780  }
781  return QVariant();
782 }
783 
784 QSizeF QgsImageLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
785 {
786  Q_UNUSED( itemHeight )
787 
788  if ( ctx && ctx->painter )
789  {
790  switch ( settings.symbolAlignment() )
791  {
792  case Qt::AlignLeft:
793  default:
794  ctx->painter->drawImage( QRectF( ctx->columnLeft, ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
795  mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
796  break;
797 
798  case Qt::AlignRight:
799  ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(), ctx->top, settings.wmsLegendSize().width(), settings.wmsLegendSize().height() ),
800  mImage, QRectF( 0, 0, mImage.width(), mImage.height() ) );
801  break;
802  }
803  }
804  return settings.wmsLegendSize();
805 }
806 
807 void QgsImageLegendNode::exportSymbolToJson( const QgsLegendSettings &, const QgsRenderContext &, QJsonObject &json ) const
808 {
809  QByteArray byteArray;
810  QBuffer buffer( &byteArray );
811  mImage.save( &buffer, "PNG" );
812  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
813  json[ "icon" ] = base64;
814 }
815 
816 // -------------------------------------------------------------------------
817 
818 QgsRasterSymbolLegendNode::QgsRasterSymbolLegendNode( QgsLayerTreeLayer *nodeLayer, const QColor &color, const QString &label, QObject *parent )
819  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
820  , mColor( color )
821  , mLabel( label )
822 {
823 }
824 
825 QVariant QgsRasterSymbolLegendNode::data( int role ) const
826 {
827  if ( role == Qt::DecorationRole )
828  {
829  const int iconSize = QgsLayerTreeModel::scaleIconSize( 16 ); // TODO: configurable?
830  QPixmap pix( iconSize, iconSize );
831  pix.fill( mColor );
832  return QIcon( pix );
833  }
834  else if ( role == Qt::DisplayRole || role == Qt::EditRole )
835  return mUserLabel.isEmpty() ? mLabel : mUserLabel;
836  else
837  return QVariant();
838 }
839 
840 
841 QSizeF QgsRasterSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
842 {
843  if ( ctx && ctx->painter )
844  {
845  QColor itemColor = mColor;
846  if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
847  {
848  if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
849  itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
850  }
851  ctx->painter->setBrush( itemColor );
852 
853  if ( settings.drawRasterStroke() )
854  {
855  QPen pen;
856  pen.setColor( settings.rasterStrokeColor() );
857  pen.setWidthF( settings.rasterStrokeWidth() );
858  pen.setJoinStyle( Qt::MiterJoin );
859  ctx->painter->setPen( pen );
860  }
861  else
862  {
863  ctx->painter->setPen( Qt::NoPen );
864  }
865 
866  switch ( settings.symbolAlignment() )
867  {
868  case Qt::AlignLeft:
869  default:
870  ctx->painter->drawRect( QRectF( ctx->columnLeft, ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2,
871  settings.symbolSize().width(), settings.symbolSize().height() ) );
872  break;
873 
874  case Qt::AlignRight:
875  ctx->painter->drawRect( QRectF( ctx->columnRight - settings.symbolSize().width(), ctx->top + ( itemHeight - settings.symbolSize().height() ) / 2,
876  settings.symbolSize().width(), settings.symbolSize().height() ) );
877  break;
878  }
879  }
880  return settings.symbolSize();
881 }
882 
883 void QgsRasterSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings, const QgsRenderContext &, QJsonObject &json ) const
884 {
885  QImage img = QImage( settings.symbolSize().toSize(), QImage::Format_ARGB32 );
886  img.fill( Qt::transparent );
887 
888  QPainter painter( &img );
889  painter.setRenderHint( QPainter::Antialiasing );
890 
891  QColor itemColor = mColor;
892  if ( QgsRasterLayer *rasterLayer = qobject_cast<QgsRasterLayer *>( layerNode()->layer() ) )
893  {
894  if ( QgsRasterRenderer *rasterRenderer = rasterLayer->renderer() )
895  itemColor.setAlpha( rasterRenderer->opacity() * 255.0 );
896  }
897  painter.setBrush( itemColor );
898 
899  if ( settings.drawRasterStroke() )
900  {
901  QPen pen;
902  pen.setColor( settings.rasterStrokeColor() );
903  pen.setWidthF( settings.rasterStrokeWidth() );
904  pen.setJoinStyle( Qt::MiterJoin );
905  painter.setPen( pen );
906  }
907  else
908  {
909  painter.setPen( Qt::NoPen );
910  }
911 
912  painter.drawRect( QRectF( 0, 0, settings.symbolSize().width(), settings.symbolSize().height() ) );
913 
914  QByteArray byteArray;
915  QBuffer buffer( &byteArray );
916  img.save( &buffer, "PNG" );
917  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
918  json[ "icon" ] = base64;
919 }
920 
921 // -------------------------------------------------------------------------
922 
924  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
925  , mValid( false )
926 {
927 }
928 
929 QImage QgsWmsLegendNode::getLegendGraphic() const
930 {
931  if ( ! mValid && ! mFetcher )
932  {
933  // or maybe in presence of a downloader we should just delete it
934  // and start a new one ?
935 
936  QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( mLayerNode->layer() );
937  const QgsLayerTreeModel *mod = model();
938  if ( ! mod )
939  return mImage;
940  const QgsMapSettings *ms = mod->legendFilterMapSettings();
941 
942  QgsRasterDataProvider *prov = layer->dataProvider();
943  if ( ! prov )
944  return mImage;
945 
946  Q_ASSERT( ! mFetcher );
947  mFetcher.reset( prov->getLegendGraphicFetcher( ms ) );
948  if ( mFetcher )
949  {
950  connect( mFetcher.get(), &QgsImageFetcher::finish, this, &QgsWmsLegendNode::getLegendGraphicFinished );
951  connect( mFetcher.get(), &QgsImageFetcher::error, this, &QgsWmsLegendNode::getLegendGraphicErrored );
952  connect( mFetcher.get(), &QgsImageFetcher::progress, this, &QgsWmsLegendNode::getLegendGraphicProgress );
953  mFetcher->start();
954  } // else QgsDebugMsg("XXX No legend supported?");
955 
956  }
957 
958  return mImage;
959 }
960 
961 QVariant QgsWmsLegendNode::data( int role ) const
962 {
963  //QgsDebugMsg( QStringLiteral("XXX data called with role %1 -- mImage size is %2x%3").arg(role).arg(mImage.width()).arg(mImage.height()) );
964 
965  if ( role == Qt::DecorationRole )
966  {
967  return QPixmap::fromImage( getLegendGraphic() );
968  }
969  else if ( role == Qt::SizeHintRole )
970  {
971  return getLegendGraphic().size();
972  }
973  return QVariant();
974 }
975 
976 QSizeF QgsWmsLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight ) const
977 {
978  Q_UNUSED( itemHeight )
979 
980  if ( ctx && ctx->painter )
981  {
982  switch ( settings.symbolAlignment() )
983  {
984  case Qt::AlignLeft:
985  default:
986  ctx->painter->drawImage( QRectF( ctx->columnLeft,
987  ctx->top,
988  settings.wmsLegendSize().width(),
989  settings.wmsLegendSize().height() ),
990  mImage,
991  QRectF( QPointF( 0, 0 ), mImage.size() ) );
992  break;
993 
994  case Qt::AlignRight:
995  ctx->painter->drawImage( QRectF( ctx->columnRight - settings.wmsLegendSize().width(),
996  ctx->top,
997  settings.wmsLegendSize().width(),
998  settings.wmsLegendSize().height() ),
999  mImage,
1000  QRectF( QPointF( 0, 0 ), mImage.size() ) );
1001  break;
1002  }
1003  }
1004  return settings.wmsLegendSize();
1005 }
1006 
1007 void QgsWmsLegendNode::exportSymbolToJson( const QgsLegendSettings &, const QgsRenderContext &, QJsonObject &json ) const
1008 {
1009  QByteArray byteArray;
1010  QBuffer buffer( &byteArray );
1011  mImage.save( &buffer, "PNG" );
1012  const QString base64 = QString::fromLatin1( byteArray.toBase64().data() );
1013  json[ "icon" ] = base64;
1014 }
1015 
1016 /* private */
1017 QImage QgsWmsLegendNode::renderMessage( const QString &msg ) const
1018 {
1019  const int fontHeight = 10;
1020  const int margin = fontHeight / 2;
1021  const int nlines = 1;
1022 
1023  const int w = 512, h = fontHeight * nlines + margin * ( nlines + 1 );
1024  QImage image( w, h, QImage::Format_ARGB32_Premultiplied );
1025  QPainter painter;
1026  painter.begin( &image );
1027  painter.setPen( QColor( 255, 0, 0 ) );
1028  painter.setFont( QFont( QStringLiteral( "Chicago" ), fontHeight ) );
1029  painter.fillRect( 0, 0, w, h, QColor( 255, 255, 255 ) );
1030  painter.drawText( 0, margin + fontHeight, msg );
1031  //painter.drawText(0,2*(margin+fontHeight),tr("retrying in 5 seconds…"));
1032  painter.end();
1033 
1034  return image;
1035 }
1036 
1037 void QgsWmsLegendNode::getLegendGraphicProgress( qint64 cur, qint64 tot )
1038 {
1039  QString msg = QStringLiteral( "Downloading... %1/%2" ).arg( cur ).arg( tot );
1040  //QgsDebugMsg ( QString("XXX %1").arg(msg) );
1041  mImage = renderMessage( msg );
1042  emit dataChanged();
1043 }
1044 
1045 void QgsWmsLegendNode::getLegendGraphicErrored( const QString &msg )
1046 {
1047  if ( ! mFetcher ) return; // must be coming after finish
1048 
1049  mImage = renderMessage( msg );
1050  //QgsDebugMsg( QStringLiteral("XXX emitting dataChanged after writing an image of %1x%2").arg(mImage.width()).arg(mImage.height()) );
1051 
1052  emit dataChanged();
1053 
1054  mFetcher.reset();
1055 
1056  mValid = true; // we consider it valid anyway
1057  // ... but remove validity after 5 seconds
1058  //QTimer::singleShot(5000, this, SLOT(invalidateMapBasedData()));
1059 }
1060 
1061 void QgsWmsLegendNode::getLegendGraphicFinished( const QImage &image )
1062 {
1063  if ( ! mFetcher ) return; // must be coming after error
1064 
1065  //QgsDebugMsg( QStringLiteral("XXX legend graphic finished, image is %1x%2").arg(theImage.width()).arg(theImage.height()) );
1066  if ( ! image.isNull() )
1067  {
1068  if ( image != mImage )
1069  {
1070  mImage = image;
1071  //QgsDebugMsg( QStringLiteral("XXX emitting dataChanged") );
1072  emit dataChanged();
1073  }
1074  mValid = true; // only if not null I guess
1075  }
1076  mFetcher.reset();
1077 }
1078 
1080 {
1081  //QgsDebugMsg( QStringLiteral("XXX invalidateMapBasedData called") );
1082  // TODO: do this only if this extent != prev extent ?
1083  mValid = false;
1084  emit dataChanged();
1085 }
1086 
1087 // -------------------------------------------------------------------------
1088 
1090  : QgsLayerTreeModelLegendNode( nodeLayer, parent )
1091  , mSettings( new QgsDataDefinedSizeLegend( settings ) )
1092 {
1093 }
1094 
1096 {
1097  delete mSettings;
1098 }
1099 
1100 QVariant QgsDataDefinedSizeLegendNode::data( int role ) const
1101 {
1102  if ( role == Qt::DecorationRole )
1103  {
1104  cacheImage();
1105  return QPixmap::fromImage( mImage );
1106  }
1107  else if ( role == Qt::SizeHintRole )
1108  {
1109  cacheImage();
1110  return mImage.size();
1111  }
1112  return QVariant();
1113 }
1114 
1116 {
1117  // setup temporary render context
1118  QgsRenderContext context;
1119  context.setScaleFactor( settings.dpi() / 25.4 );
1120  context.setRendererScale( settings.mapScale() );
1121  context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
1122  context.setForceVectorOutput( true );
1123 
1124  if ( ctx && ctx->painter )
1125  {
1126  context.setPainter( ctx->painter );
1127  ctx->painter->save();
1128  ctx->painter->setRenderHint( QPainter::Antialiasing );
1129  ctx->painter->translate( ctx->columnLeft, ctx->top );
1130  ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
1131  }
1132 
1133  QgsDataDefinedSizeLegend ddsLegend( *mSettings );
1134  ddsLegend.setFont( settings.style( QgsLegendStyle::SymbolLabel ).font() );
1135  ddsLegend.setTextColor( settings.fontColor() );
1136 
1137  QSize contentSize;
1138  int labelXOffset;
1139  ddsLegend.drawCollapsedLegend( context, &contentSize, &labelXOffset );
1140 
1141  if ( ctx && ctx->painter )
1142  ctx->painter->restore();
1143 
1144  ItemMetrics im;
1145  im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
1146  im.labelSize = QSizeF( labelXOffset / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
1147  return im;
1148 }
1149 
1150 
1151 void QgsDataDefinedSizeLegendNode::cacheImage() const
1152 {
1153  if ( mImage.isNull() )
1154  {
1155  std::unique_ptr<QgsRenderContext> context( createTemporaryRenderContext() );
1156  if ( !context )
1157  {
1158  context.reset( new QgsRenderContext );
1159  context->setScaleFactor( 96 / 25.4 );
1160  }
1161  mImage = mSettings->collapsedLegendImage( *context );
1162  }
1163 }
void exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
Q_NOWARN_DEPRECATED_POP QgsRenderContext * context
Render context, if available.
void setForceVectorOutput(bool force)
Sets whether rendering operations should use vector operations instead of any faster raster shortcuts...
void drawText(QPainter *p, double x, double y, const QString &text, const QFont &font) const
Draws Text.
virtual QgsLegendSymbolList legendSymbolItems() const
Returns a list of symbology items for the legend.
Single variable definition for use within a QgsExpressionContextScope.
QgsDataDefinedSizeLegendNode(QgsLayerTreeLayer *nodeLayer, const QgsDataDefinedSizeLegend &settings, QObject *parent=nullptr)
Construct the node using QgsDataDefinedSizeLegend as definition of the node&#39;s appearance.
void drawPreviewIcon(QPainter *painter, QSize size, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr)
Draws an icon of the symbol that occupies an area given by size using the specified painter...
Definition: qgssymbol.cpp:495
double columnRight
Right side of current legend column.
virtual Qt::ItemFlags flags() const
Returns item flags associated with the item. Default implementation returns Qt::ItemIsEnabled.
double mapScale() const
Returns the legend map scale.
QString labelExpression() const
Returns the expression member of the LayerTreeNode.
QgsRenderContext * createTemporaryRenderContext() const
Returns a temporary context or nullptr if legendMapViewData are not valid.
QList< QgsLegendSymbolItem > QgsLegendSymbolList
Text at point of origin draw mode.
QgsSymbol * symbol() const
Returns associated symbol. May be nullptr.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
QString ruleKey() const
Returns unique identifier of the rule for identification of the item within renderer.
bool useAdvancedEffects() const
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
virtual QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const
Draws symbol on the left side of the item.
void setFont(const QFont &font)
Sets font used for rendering of labels - only valid for collapsed legend.
Use antialiasing while drawing.
QgsImageLegendNode(QgsLayerTreeLayer *nodeLayer, const QImage &img, QObject *parent=nullptr)
Constructor for QgsImageLegendNode.
virtual bool setData(const QVariant &value, int role)
Sets some data associated with the item. Default implementation does nothing and returns false...
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...
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
QgsSymbolLegendNode(QgsLayerTreeLayer *nodeLayer, const QgsLegendSymbolItem &item, QObject *parent=nullptr)
Constructor for QgsSymbolLegendNode.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
bool testFlag(Flag f) const
Check whether a flag is enabled.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:280
void emitStyleChanged()
Triggers an emission of the styleChanged() signal.
double margin(Side side)
Returns the margin (in mm) for the specified side of the component.
void setRendererScale(double scale)
Sets the renderer map scale.
QFont font() const
Returns the font used for rendering this legend component.
Qt::AlignmentFlag symbolAlignment() const
Returns the alignment for placement of legend symbols.
virtual QgsImageFetcher * getLegendGraphicFetcher(const QgsMapSettings *mapSettings)
Returns a new image downloader for the raster legend.
void invalidateMapBasedData() override
Notification from model that information from associated map view has changed.
void invalidateMapBasedData() override
Notification from model that information from associated map view has changed.
QgsLayerTreeLayer * layerNode() const
Returns pointer to the parent layer node.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
bool drawRasterStroke() const
Returns whether a stroke will be drawn around raster symbol items.
Line symbol.
Definition: qgssymbol.h:86
double textWidthMillimeters(const QFont &font, const QString &text) const
Returns the font width in millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCALE...
void exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
QgsLayerTreeModelLegendNode(QgsLayerTreeLayer *nodeL, QObject *parent=nullptr)
Construct the node with pointer to its parent layer node.
QString label() const
Returns text label.
QgsWmsLegendNode(QgsLayerTreeLayer *nodeLayer, QObject *parent=nullptr)
Constructor for QgsWmsLegendNode.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:860
QColor rasterStrokeColor() const
Returns the stroke color for the stroke drawn around raster symbol items.
void exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
The QgsMapSettings class contains configuration for rendering of the map.
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:234
void toggleAllItems()
Toggle all items belonging to the same layer as this node.
QSize minimumIconSize() const
Calculates the minimum icon size to prevent cropping.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:37
The QgsLayerTreeModel class is model implementation for Qt item views framework.
QSizeF wmsLegendSize() const
Rule key of the parent legend node - for legends with tree hierarchy (QString). Added in 2...
QgsLegendStyle style(QgsLegendStyle::Style s) const
Returns style.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
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 exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json) const override
Adds a symbol in base64 string within a JSON object with the key "icon".
QString name() const override
Returns the layer&#39;s name.
void setScaleFactor(double factor)
Sets the scaling factor for the render to convert painter units to physical sizes.
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted...
static int scaleIconSize(int standardSize)
Scales an layer tree model icon size to compensate for display pixel density, making the icon size hi...
Qt::ItemFlags flags() const override
Returns item flags associated with the item. Default implementation returns Qt::ItemIsEnabled.
void setSymbol(QgsSymbol *s)
Sets the symbol of the item.
QgsRasterSymbolLegendNode(QgsLayerTreeLayer *nodeLayer, const QColor &color, const QString &label, QObject *parent=nullptr)
Constructor for QgsRasterSymbolLegendNode.
long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
void checkAllItems()
Checks all items belonging to the same layer as this node.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void error(const QString &msg)
Emitted when an error occurs.
double rasterStrokeWidth() const
Returns the stroke width (in millimeters) for the stroke drawn around raster symbol items...
QgsLayerTreeModel * model() const
Returns pointer to model owning this legend node.
The QgsLegendSettings class stores the appearance and layout settings for legend drawing with QgsLege...
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...
ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx) override
Entry point called from QgsLegendRenderer to do the rendering.
Symbol icon (excluding label)
void setPainter(QPainter *p)
Sets the destination QPainter for the render operation.
virtual bool legendSymbolItemChecked(const QString &key)
items of symbology items in legend is checked
static double estimateMaxSymbolBleed(QgsSymbol *symbol, const QgsRenderContext &context)
Returns the maximum estimated bleed for the symbol.
QgsFeatureRenderer * renderer()
Returns renderer.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
double maxSiblingSymbolWidth
Largest symbol width, considering all other sibling legend components associated with the current com...
QString symbolLabel() const
Label of the symbol, user defined label will be used, otherwise will default to the label made by QGI...
Single scope for storing variables and functions for use within a QgsExpressionContext.
void dataChanged()
Emitted on internal data change so the layer tree model can forward the signal to views...
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window&#39;s toolbar icons.
void symbolFeatureCountMapChanged()
Emitted when the feature count for symbols on this layer has been recalculated.
Qt::Alignment alignment() const
Returns the alignment for the legend component.
virtual void checkLegendSymbolItem(const QString &key, bool state=true)
item in symbology was checked
virtual void setLegendSymbolItem(const QString &key, QgsSymbol *symbol)
Sets the symbol to be used for a legend symbol item.
bool isCheckable() const
Returns whether the item is user-checkable - whether renderer supports enabling/disabling it...
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
QSizeF symbolSize() const
static void drawText(const QRectF &rect, double rotation, HAlignment alignment, const QStringList &textLines, QgsRenderContext &context, const QgsTextFormat &format, bool drawAsOutlines=true)
Draws text within a rectangle using the specified settings.
double fontHeightCharacterMM(const QFont &font, QChar c) const
Returns the font height of a character in millimeters.
virtual ItemMetrics draw(const QgsLegendSettings &settings, ItemContext *ctx)
Entry point called from QgsLegendRenderer to do the rendering.
QgsExpressionContext & expressionContext()
Gets the expression context.
void setEmbeddedInParent(bool embedded) override
QgsMapLayer * layer() const
Returns the map layer associated with this node.
void setSymbol(QgsSymbol *symbol)
Sets the symbol to be used by the legend node.
double top
Top y-position of legend item.
const QgsSymbol * symbol() const
Returns the symbol used by the legend node.
void exportToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json)
Entry point called from QgsLegendRenderer to do the rendering in a JSON object.
Marker symbol.
Definition: qgssymbol.h:85
QgsSimpleLegendNode(QgsLayerTreeLayer *nodeLayer, const QString &label, const QIcon &icon=QIcon(), QObject *parent=nullptr, const QString &key=QString())
Constructor for QgsSimpleLegendNode.
virtual void setEmbeddedInParent(bool embedded)
QFont scaledFont(const QgsRenderContext &context) const
Returns a font with the size scaled to match the format&#39;s size settings (including units and map unit...
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Contains information about the context of a rendering operation.
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:120
QSizeF drawSymbol(const QgsLegendSettings &settings, ItemContext *ctx, double itemHeight) const override
Draws symbol on the left side of the item.
bool setData(const QVariant &value, int role) override
Sets some data associated with the item. Default implementation does nothing and returns false...
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr)
Returns a pixmap preview for a color ramp.
virtual void exportSymbolToJson(const QgsLegendSettings &settings, const QgsRenderContext &context, QJsonObject &json) const
Adds a symbol in base64 string within a JSON object with the key "icon".
double columnLeft
Left side of current legend column.
void setMapToPixel(const QgsMapToPixel &mtp)
Sets the context&#39;s map to pixel transform, which transforms between map coordinates and device coordi...
virtual QVariant data(int role) const =0
Returns data associated with the item. Must be implemented in derived class.
void legendMapViewData(double *mapUnitsPerPixel, int *dpi, double *scale) const
Gets hints about map view - to be used in legend nodes.
static QRect nonTransparentImageRect(const QImage &image, QSize minSize=QSize(), bool center=false)
Calculates the non-transparent region of an image.
The QgsLegendRendererItem class is abstract interface for legend items returned from QgsMapLayerLegen...
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
void uncheckAllItems()
Unchecks all items belonging to the same layer as this node.
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
void setTextColor(const QColor &color)
Sets text color for rendering of labels - only valid for collapsed legend.
virtual QSizeF drawSymbolText(const QgsLegendSettings &settings, ItemContext *ctx, QSizeF symbolSize) const
Draws label on the right side of the item.
QString parentRuleKey() const
Key of the parent legend node.
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
void drawCollapsedLegend(QgsRenderContext &context, QSize *outputSize SIP_OUT=nullptr, int *labelXOffset SIP_OUT=nullptr) const
Draw the legend if using LegendOneNodeForAll and optionally output size of the legend and x offset of...
Symbol label (excluding icon)
double lineSpacing() const
For legends that support it, will show them in a tree instead of a list (needs also ShowLegend)...
QColor fontColor() const
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.
double scaleFactor() const
Returns the scaling factor for the render to convert painter units to physical sizes.
Represents a vector layer which manages a vector based data sets.
void finish(const QImage &legend)
Emitted when the download completes.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
QVariant data(int role) const override
Returns data associated with the item. Must be implemented in derived class.
int level() const
Indentation level that tells how deep the item is in a hierarchy of items. For flat lists level is 0...
double fontDescentMillimeters(const QFont &font) const
Returns the font descent in Millimeters (considers upscaling and downscaling with FONT_WORKAROUND_SCA...
QString evaluateLabel(const QgsExpressionContext &context=QgsExpressionContext(), const QString &label=QString())
Evaluates and returns the text label of the current node.
double mmPerMapUnit() const
Raster renderer pipe that applies colors to a raster.
void exportSymbolTextToJson(const QgsLegendSettings &settings, QJsonObject &json) const
Adds a label in a JSON object with the key "title".
void progress(qint64 received, qint64 total)
Emitted to report progress.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
Layer tree node points to a map layer.
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...
Base class for raster data providers.
static double textHeight(const QgsRenderContext &context, const QgsTextFormat &format, const QStringList &textLines, DrawMode mode, QFontMetricsF *fontMetrics=nullptr)
Returns the height of a text based on a given format.