QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsvectorlayerlegendwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerlegendwidget.cpp
3  ---------------------
4  Date : April 2018
5  Copyright : (C) 2018 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
17 
18 #include <QBoxLayout>
19 #include <QStandardItemModel>
20 #include <QTreeView>
21 #include <QTreeWidget>
22 
25 #include "qgsmapcanvas.h"
26 #include "qgsmaplayerlegend.h"
27 #include "qgsrenderer.h"
28 #include "qgsrulebasedlabeling.h"
29 #include "qgssymbollayerutils.h"
30 #include "qgstextformatwidget.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsfontbutton.h"
33 
35  : QWidget( parent )
36 {
37  mLegendTreeView = new QTreeView;
38  mLegendTreeView->setRootIsDecorated( false );
39 
40  mTextOnSymbolFormatButton = new QgsFontButton( nullptr, tr( "Legend Text Format" ) );
41  mTextOnSymbolFormatButton->setText( tr( "Text Format" ) );
42  mTextOnSymbolFormatButton->setMode( QgsFontButton::ModeTextRenderer );
43 
44  mTextOnSymbolFromExpressionButton = new QPushButton( tr( "Set Labels from Expression…" ) );
45  connect( mTextOnSymbolFromExpressionButton, &QPushButton::clicked, this, &QgsVectorLayerLegendWidget::labelsFromExpression );
46 
47  mTextOnSymbolGroupBox = new QgsCollapsibleGroupBox;
48 
49  QHBoxLayout *buttonsLayout = new QHBoxLayout;
50  buttonsLayout->addWidget( mTextOnSymbolFormatButton );
51  buttonsLayout->addWidget( mTextOnSymbolFromExpressionButton );
52  buttonsLayout->addStretch();
53 
54  QVBoxLayout *groupLayout = new QVBoxLayout;
55  groupLayout->addWidget( mLegendTreeView );
56  groupLayout->addLayout( buttonsLayout );
57 
58  mTextOnSymbolGroupBox->setTitle( tr( "Text on Symbols" ) );
59  mTextOnSymbolGroupBox->setCheckable( true );
60  mTextOnSymbolGroupBox->setLayout( groupLayout );
61  mTextOnSymbolGroupBox->setCollapsed( false );
62 
63  mLabelLegendGroupBox = new QgsCollapsibleGroupBox;
64  mLabelLegendGroupBox->setCheckable( true );
65  mLabelLegendGroupBox->setTitle( tr( "Show Label Legend" ) );
66 
67  mLabelLegendTreeWidget = new QTreeWidget;
68  connect( mLabelLegendTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerLegendWidget::labelLegendTreeWidgetItemDoubleClicked );
69  QVBoxLayout *labelLegendLayout = new QVBoxLayout;
70  labelLegendLayout->addWidget( mLabelLegendTreeWidget );
71  mLabelLegendGroupBox->setLayout( labelLegendLayout );
72 
73  mPlaceholderImageLabel = new QLabel( tr( "Legend placeholder image" ) );
74  mImageSourceLineEdit = new QgsImageSourceLineEdit();
75  mImageSourceLineEdit->setLastPathSettingsKey( QStringLiteral( "lastLegendPlaceholderDir" ) );
76  if ( mLayer )
77  {
78  mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() );
79  }
80 
81  QHBoxLayout *placeholderLayout = new QHBoxLayout;
82  placeholderLayout->addWidget( mPlaceholderImageLabel );
83  placeholderLayout->addWidget( mImageSourceLineEdit );
84 
85  QVBoxLayout *layout = new QVBoxLayout;
86  layout->setContentsMargins( 0, 0, 0, 0 );
87  layout->addLayout( placeholderLayout );
88  layout->addWidget( mLabelLegendGroupBox );
89  layout->addWidget( mTextOnSymbolGroupBox );
90 
91  setLayout( layout );
92 }
93 
94 void QgsVectorLayerLegendWidget::labelLegendTreeWidgetItemDoubleClicked( QTreeWidgetItem *item, int column )
95 {
96  const Qt::ItemFlags flags = item->flags();
97  if ( column == 1 )
98  {
99  item->setFlags( flags | Qt::ItemIsEditable );
100  }
101  else
102  {
103  item->setFlags( flags & ( ~Qt::ItemIsEditable ) );
104  }
105 }
106 
108 {
109  mCanvas = canvas;
110  mTextOnSymbolFormatButton->setMapCanvas( mCanvas );
111 }
112 
114 {
115  mLayer = layer;
116 
117  QgsDefaultVectorLayerLegend *legend = qobject_cast<QgsDefaultVectorLayerLegend *>( layer->legend() );
118  if ( !legend )
119  return;
120 
121  mLabelLegendGroupBox->setChecked( legend->showLabelLegend() );
122  populateLabelLegendTreeWidget();
123  mTextOnSymbolGroupBox->setChecked( legend->textOnSymbolEnabled() );
124  mTextOnSymbolFormatButton->setTextFormat( legend->textOnSymbolTextFormat() );
125  populateLegendTreeView( legend->textOnSymbolContent() );
126  if ( mLayer )
127  {
128  mImageSourceLineEdit->setSource( mLayer->legendPlaceholderImage() );
129  }
130 }
131 
132 void QgsVectorLayerLegendWidget::populateLabelLegendTreeWidget()
133 {
134  mLabelLegendTreeWidget->clear();
135  mLabelLegendTreeWidget->setColumnCount( 2 );
136  QTreeWidgetItem *headerItem = new QTreeWidgetItem( QStringList() << tr( "Description" ) << tr( "Legend Text" ) );
137  mLabelLegendTreeWidget->setHeaderItem( headerItem );
138 
139  const QgsAbstractVectorLayerLabeling *labeling = mLayer->labeling();
140  if ( labeling )
141  {
142  const QStringList pList = labeling->subProviders();
143  for ( int i = 0; i < pList.size(); ++i )
144  {
145  const QgsPalLayerSettings s = labeling->settings( pList.at( i ) );
146  QString description;
147  const QgsRuleBasedLabeling *ruleBasedLabeling = dynamic_cast<const QgsRuleBasedLabeling *>( labeling );
148  if ( ruleBasedLabeling && ruleBasedLabeling->rootRule() )
149  {
150  const QgsRuleBasedLabeling::Rule *rule = ruleBasedLabeling->rootRule()->findRuleByKey( pList.at( i ) );
151  if ( rule )
152  {
153  description = rule->description();
154  }
155  }
156 
157  QTreeWidgetItem *labelItem = new QTreeWidgetItem( QStringList() << description << s.legendString() );
158  labelItem->setData( 0, Qt::UserRole, pList.at( i ) );
159  mLabelLegendTreeWidget->addTopLevelItem( labelItem );
160  }
161  }
162 }
163 
164 
165 void QgsVectorLayerLegendWidget::populateLegendTreeView( const QHash<QString, QString> &content )
166 {
167  QStandardItemModel *model = new QStandardItemModel( this );
168  model->setColumnCount( 2 );
169  model->setHorizontalHeaderLabels( QStringList() << tr( "Symbol" ) << tr( "Text" ) );
170 
171  const QgsLegendSymbolList lst = mLayer->renderer() ? mLayer->renderer()->legendSymbolItems() : QgsLegendSymbolList();
172  for ( const QgsLegendSymbolItem &symbolItem : lst )
173  {
174  if ( !symbolItem.symbol() )
175  continue;
176 
177  QgsRenderContext context;
178  const QSize iconSize( 16, 16 );
179  const QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbolItem.symbol(), iconSize, 0, &context );
180 
181  QStandardItem *item1 = new QStandardItem( icon, symbolItem.label() );
182  item1->setEditable( false );
183  QStandardItem *item2 = new QStandardItem;
184  if ( symbolItem.ruleKey().isEmpty() )
185  {
186  item1->setEnabled( false );
187  item2->setEnabled( false );
188  }
189  else
190  {
191  item1->setData( symbolItem.ruleKey() );
192  if ( content.contains( symbolItem.ruleKey() ) )
193  item2->setText( content.value( symbolItem.ruleKey() ) );
194  }
195  model->appendRow( QList<QStandardItem *>() << item1 << item2 );
196  }
197  mLegendTreeView->setModel( model );
198  mLegendTreeView->resizeColumnToContents( 0 );
199 }
200 
201 
203 {
205  legend->setTextOnSymbolEnabled( mTextOnSymbolGroupBox->isChecked() );
206  legend->setTextOnSymbolTextFormat( mTextOnSymbolFormatButton->textFormat() );
207 
208  QHash<QString, QString> content;
209  if ( QStandardItemModel *model = qobject_cast<QStandardItemModel *>( mLegendTreeView->model() ) )
210  {
211  for ( int i = 0; i < model->rowCount(); ++i )
212  {
213  const QString ruleKey = model->item( i, 0 )->data().toString();
214  const QString label = model->item( i, 1 )->text();
215  if ( !label.isEmpty() )
216  content[ruleKey] = label;
217  }
218  }
219  legend->setTextOnSymbolContent( content );
220 
221  const bool showLabelLegend = mLabelLegendGroupBox->isChecked();
222  legend->setShowLabelLegend( showLabelLegend );
223  if ( showLabelLegend )
224  {
225  applyLabelLegend();
226  }
227 
228  mLayer->setLegendPlaceholderImage( mImageSourceLineEdit->source() );
229 
230  mLayer->setLegend( legend );
231 }
232 
233 void QgsVectorLayerLegendWidget::labelsFromExpression()
234 {
235  QHash<QString, QString> content;
237 
238  QgsExpressionBuilderDialog dlgExpression( mLayer );
239  dlgExpression.setExpressionContext( context.expressionContext() );
240  if ( !dlgExpression.exec() )
241  return;
242 
243  QgsExpression expr( dlgExpression.expressionText() );
244  expr.prepare( &context.expressionContext() );
245 
246  std::unique_ptr< QgsFeatureRenderer > r( mLayer->renderer()->clone() );
247 
248  QgsFeature f;
249  QgsFeatureRequest request;
250  request.setSubsetOfAttributes( r->usedAttributes( context ), mLayer->fields() );
251  QgsFeatureIterator fi = mLayer->getFeatures();
252 
253  r->startRender( context, mLayer->fields() );
254  while ( fi.nextFeature( f ) )
255  {
256  context.expressionContext().setFeature( f );
257  const QSet<QString> keys = r->legendKeysForFeature( f, context );
258  for ( const QString &key : keys )
259  {
260  if ( content.contains( key ) )
261  continue;
262 
263  const QString label = expr.evaluate( &context.expressionContext() ).toString();
264  if ( !label.isEmpty() )
265  content[key] = label;
266  }
267  }
268  r->stopRender( context );
269 
270  populateLegendTreeView( content );
271 }
272 
273 void QgsVectorLayerLegendWidget::applyLabelLegend()
274 {
275  const QgsAbstractVectorLayerLabeling *layerLabeling = mLayer->labeling();
276  if ( !layerLabeling )
277  {
278  return;
279  }
280 
281  QgsAbstractVectorLayerLabeling *labeling = layerLabeling->clone();
282  const QStringList ids = labeling->subProviders();
283  const int nIterations = std::min< int >( ids.size(), mLabelLegendTreeWidget->topLevelItemCount() );
284 
285  for ( int i = 0; i < nIterations; ++i )
286  {
287  QTreeWidgetItem *item = mLabelLegendTreeWidget->topLevelItem( i );
288  if ( item )
289  {
290  const QString legendText = item->text( 1 );
291 
292  QgsPalLayerSettings *s = new QgsPalLayerSettings( labeling->settings( ids.at( i ) ) );
293  s->setLegendString( legendText );
294  labeling->setSettings( s, ids.at( i ) );
295  }
296  }
297 
298  mLayer->setLabeling( labeling );
299 }
QgsVectorLayer::getFeatures
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
Definition: qgsvectorlayer.cpp:1052
QgsVectorLayerLegendWidget::QgsVectorLayerLegendWidget
QgsVectorLayerLegendWidget(QWidget *parent=nullptr)
Definition: qgsvectorlayerlegendwidget.cpp:34
QgsDefaultVectorLayerLegend
Default legend implementation for vector layers.
Definition: qgsmaplayerlegend.h:236
QgsRuleBasedLabeling::rootRule
QgsRuleBasedLabeling::Rule * rootRule()
Definition: qgsrulebasedlabeling.cpp:460
QgsRuleBasedLabeling::Rule
A child rule for QgsRuleBasedLabeling.
Definition: qgsrulebasedlabeling.h:55
QgsRenderContext::expressionContext
QgsExpressionContext & expressionContext()
Gets the expression context.
Definition: qgsrendercontext.h:625
qgsmapcanvas.h
QgsRenderContext::fromMapSettings
static QgsRenderContext fromMapSettings(const QgsMapSettings &mapSettings)
create initialized QgsRenderContext instance from given QgsMapSettings
Definition: qgsrendercontext.cpp:234
QgsPalLayerSettings
Contains settings for how a map layer will be labeled.
Definition: qgspallabeling.h:86
QgsMapCanvas::mapSettings
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Definition: qgsmapcanvas.cpp:437
QgsFontButton::setTextFormat
void setTextFormat(const QgsTextFormat &format)
Sets the current text format to show in the widget.
Definition: qgsfontbutton.cpp:151
qgssymbollayerutils.h
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
QgsRuleBasedLabeling::Rule::findRuleByKey
const QgsRuleBasedLabeling::Rule * findRuleByKey(const QString &key) const
Try to find a rule given its unique key.
Definition: qgsrulebasedlabeling.cpp:201
QgsRenderContext
Contains information about the context of a rendering operation.
Definition: qgsrendercontext.h:59
QgsFeatureRenderer::legendSymbolItems
virtual QgsLegendSymbolList legendSymbolItems() const
Returns a list of symbology items for the legend.
Definition: qgsrenderer.cpp:377
QgsFeatureRequest::setSubsetOfAttributes
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
Definition: qgsfeaturerequest.cpp:228
QgsCollapsibleGroupBoxBasic::setCollapsed
void setCollapsed(bool collapse)
Collapse or uncollapse this groupbox.
Definition: qgscollapsiblegroupbox.cpp:405
QgsPalLayerSettings::legendString
QString legendString() const
legendString
Definition: qgspallabeling.h:751
QgsMapLayer::legend
QgsMapLayerLegend * legend() const
Can be nullptr.
Definition: qgsmaplayer.cpp:2087
QgsCollapsibleGroupBox
A groupbox that collapses/expands when toggled and can save its collapsed and checked states....
Definition: qgscollapsiblegroupbox.h:185
QgsRuleBasedLabeling
Rule based labeling for a vector layer.
Definition: qgsrulebasedlabeling.h:42
QgsAbstractVectorLayerLabeling::setSettings
virtual void setSettings(QgsPalLayerSettings *settings, const QString &providerId=QString())=0
Set pal settings for a specific provider (takes ownership).
QgsGuiUtils::iconSize
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
Definition: qgsguiutils.cpp:264
QgsVectorLayer::fields
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Definition: qgsvectorlayer.cpp:3436
QgsVectorLayerLegendWidget::setMapCanvas
void setMapCanvas(QgsMapCanvas *canvas)
Sets pointer to map canvas.
Definition: qgsvectorlayerlegendwidget.cpp:107
QgsFontButton::setMapCanvas
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the widget.
Definition: qgsfontbutton.cpp:136
QgsLegendSymbolItem
The class stores information about one class/rule of a vector layer renderer in a unified way that ca...
Definition: qgslegendsymbolitem.h:36
QgsFeatureRequest
This class wraps a request for features to a vector layer (or directly its vector data provider).
Definition: qgsfeaturerequest.h:83
QgsVectorLayer::setLabeling
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
Definition: qgsvectorlayer.cpp:1482
QgsPalLayerSettings::setLegendString
void setLegendString(const QString &legendString)
setLegendString
Definition: qgspallabeling.h:745
qgstextformatwidget.h
qgsrulebasedlabeling.h
QgsSymbolLayerUtils::symbolPreviewPixmap
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.
Definition: qgssymbollayerutils.cpp:876
qgsvectorlayerlegendwidget.h
QgsAbstractVectorLayerLabeling::subProviders
virtual QStringList subProviders() const
Gets list of sub-providers within the layer's labeling.
Definition: qgsvectorlayerlabeling.h:76
QgsDefaultVectorLayerLegend::textOnSymbolEnabled
bool textOnSymbolEnabled() const
Returns whether the "text on symbol" functionality is enabled.
Definition: qgsmaplayerlegend.h:249
QgsFeatureRenderer::clone
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
QgsVectorLayer::labeling
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
Definition: qgsvectorlayer.h:1656
QgsExpressionBuilderDialog
A generic dialog for building expression strings.
Definition: qgsexpressionbuilderdialog.h:30
QgsVectorLayerLegendWidget::setLayer
void setLayer(QgsVectorLayer *layer)
Initialize widget with a map layer.
Definition: qgsvectorlayerlegendwidget.cpp:113
qgsfontbutton.h
qgsrenderer.h
QgsMapLayer::legendPlaceholderImage
QString legendPlaceholderImage() const
Returns path to the placeholder image or an empty string if a generated legend is shown.
Definition: qgsmaplayer.h:1516
QgsVectorLayerLegendWidget::applyToLayer
void applyToLayer()
Store changes made in the widget to the layer.
Definition: qgsvectorlayerlegendwidget.cpp:202
QgsFontButton::textFormat
QgsTextFormat textFormat
Definition: qgsfontbutton.h:54
QgsAbstractVectorLayerLabeling
Abstract base class - its implementations define different approaches to the labeling of a vector lay...
Definition: qgsvectorlayerlabeling.h:41
qgsvectorlayer.h
QgsAbstractFileContentSourceLineEdit::setLastPathSettingsKey
void setLastPathSettingsKey(const QString &key)
Sets a specific settings key to use when storing the last used path for the file source.
Definition: qgsfilecontentsourcelineedit.cpp:105
qgsfilecontentsourcelineedit.h
QgsFontButton
A button for customizing QgsTextFormat settings.
Definition: qgsfontbutton.h:47
QgsDefaultVectorLayerLegend::setTextOnSymbolEnabled
void setTextOnSymbolEnabled(bool enabled)
Sets whether the "text on symbol" functionality is enabled.
Definition: qgsmaplayerlegend.h:257
QgsFontButton::ModeTextRenderer
@ ModeTextRenderer
Configure font settings for use with QgsTextRenderer.
Definition: qgsfontbutton.h:61
QgsDefaultVectorLayerLegend::setTextOnSymbolContent
void setTextOnSymbolContent(const QHash< QString, QString > &content)
Sets per-symbol content of labels for "text on symbol" functionality.
Definition: qgsmaplayerlegend.h:296
QgsFeatureIterator::nextFeature
bool nextFeature(QgsFeature &f)
Definition: qgsfeatureiterator.h:399
QgsVectorLayer
Represents a vector layer which manages a vector based data sets.
Definition: qgsvectorlayer.h:391
QgsRuleBasedLabeling::Rule::description
QString description() const
A human readable description for this rule.
Definition: qgsrulebasedlabeling.h:118
QgsAbstractFileContentSourceLineEdit::setSource
void setSource(const QString &source)
Sets a new source to show in the widget.
Definition: qgsfilecontentsourcelineedit.cpp:116
QgsDefaultVectorLayerLegend::showLabelLegend
bool showLabelLegend() const
Returns whether the legend for the labeling is shown.
Definition: qgsmaplayerlegend.h:263
QgsDefaultVectorLayerLegend::setTextOnSymbolTextFormat
void setTextOnSymbolTextFormat(const QgsTextFormat &format)
Sets text format of symbol labels for "text on symbol" functionality.
Definition: qgsmaplayerlegend.h:282
qgsmaplayerlegend.h
QgsFeature
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:55
QgsDefaultVectorLayerLegend::textOnSymbolContent
QHash< QString, QString > textOnSymbolContent() const
Returns per-symbol content of labels for "text on symbol" functionality.
Definition: qgsmaplayerlegend.h:289
QgsImageSourceLineEdit
A line edit widget with toolbutton for setting a raster image path.
Definition: qgsfilecontentsourcelineedit.h:278
QgsMapLayer::setLegendPlaceholderImage
void setLegendPlaceholderImage(const QString &imgPath)
Set placeholder image for legend.
Definition: qgsmaplayer.h:1523
QgsExpression
Class for parsing and evaluation of expressions (formerly called "search strings")....
Definition: qgsexpression.h:102
QgsLegendSymbolList
QList< QgsLegendSymbolItem > QgsLegendSymbolList
Definition: qgslegendsymbolitem.h:144
QgsFeatureIterator
Wrapper for iterator of features from vector data provider or vector layer.
Definition: qgsfeatureiterator.h:289
QgsFontButton::setMode
void setMode(Mode mode)
Sets the current button mode.
Definition: qgsfontbutton.cpp:784
QgsDefaultVectorLayerLegend::textOnSymbolTextFormat
QgsTextFormat textOnSymbolTextFormat() const
Returns text format of symbol labels for "text on symbol" functionality.
Definition: qgsmaplayerlegend.h:276
QgsMapLayer::setLegend
void setLegend(QgsMapLayerLegend *legend)
Assign a legend controller to the map layer.
Definition: qgsmaplayer.cpp:2070
QgsAbstractVectorLayerLabeling::settings
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
QgsDefaultVectorLayerLegend::setShowLabelLegend
void setShowLabelLegend(bool enabled)
Sets if a legend for the labeling should be shown.
Definition: qgsmaplayerlegend.h:270
QgsAbstractVectorLayerLabeling::clone
virtual QgsAbstractVectorLayerLabeling * clone() const =0
Returns a new copy of the object.
QgsExpressionContext::setFeature
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Definition: qgsexpressioncontext.cpp:525
QgsVectorLayer::renderer
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
Definition: qgsvectorlayer.h:903
QgsAbstractFileContentSourceLineEdit::source
QString source
Definition: qgsfilecontentsourcelineedit.h:43
qgsexpressionbuilderdialog.h