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