QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgspointdisplacementrendererwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgspointdisplacementrendererwidget.cpp
3 --------------------------------------
4 begin : January 26, 2010
5 copyright : (C) 2010 by Marco Hugentobler
6 email : marco at hugis dot net
7 ***************************************************************************/
8
9/***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
19
20#include "qgsapplication.h"
21#include "qgsfields.h"
22#include "qgsmarkersymbol.h"
24#include "qgsrendererregistry.h"
25#include "qgsstyle.h"
27#include "qgsvectorlayer.h"
28
29#include <QString>
30
31#include "moc_qgspointdisplacementrendererwidget.cpp"
32
33using namespace Qt::StringLiterals;
34
39
41 : QgsRendererWidget( layer, style )
42
43{
44 if ( !layer )
45 {
46 return;
47 }
48
49 //the renderer only applies to point vector layers
51 {
52 //setup blank dialog
53 mRenderer = nullptr;
54 setupBlankUi( layer->name() );
55 return;
56 }
57 setupUi( this );
58 connect( mLabelFieldComboBox, &QComboBox::currentTextChanged, this, &QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged );
59 connect( mRendererComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged );
60 connect( mPlacementComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged );
61 connect( mCircleWidthSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged );
62 connect( mCircleColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged );
63 connect( mDistanceSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged );
64 connect( mDistanceUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed );
65 connect( mLabelColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged );
66 connect( mCircleModificationSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged );
67 connect( mLabelDistanceFactorSpinBox, static_cast<void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged );
68 connect( mScaleDependentLabelsCheckBox, &QCheckBox::stateChanged, this, &QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged );
69 connect( mRendererSettingsButton, &QPushButton::clicked, this, &QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked );
70 this->layout()->setContentsMargins( 0, 0, 0, 0 );
71
72 mLabelFontButton->setMode( QgsFontButton::ModeQFont );
74 mCenterSymbolToolButton->setSymbolType( Qgis::SymbolType::Marker );
75
76 if ( renderer )
77 {
79 }
80 if ( !mRenderer )
81 {
82 mRenderer = std::make_unique<QgsPointDisplacementRenderer>();
83 if ( renderer )
84 renderer->copyRendererData( mRenderer.get() );
85 }
86
87 blockAllSignals( true );
88
89 mPlacementComboBox->addItem( tr( "Ring" ), QgsPointDisplacementRenderer::Ring );
90 mPlacementComboBox->addItem( tr( "Concentric Rings" ), QgsPointDisplacementRenderer::ConcentricRings );
91 mPlacementComboBox->addItem( tr( "Grid" ), QgsPointDisplacementRenderer::Grid );
92
93 //insert attributes into combo box
94 if ( layer )
95 {
96 const QgsFields layerFields = layer->fields();
97 for ( const QgsField &f : layerFields )
98 {
99 mLabelFieldComboBox->addItem( f.name() );
100 }
101 mLabelFieldComboBox->addItem( tr( "None" ) );
102
103 const QString currentLabelAttribute = mRenderer->labelAttributeName();
104 if ( !currentLabelAttribute.isEmpty() )
105 {
106 mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( currentLabelAttribute ) );
107 }
108 else
109 {
110 mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( tr( "None" ) ) );
111 }
112 }
113
114 //insert possible renderer types
116 QStringList::const_iterator it = rendererList.constBegin();
117 for ( ; it != rendererList.constEnd(); ++it )
118 {
119 if ( *it != "pointDisplacement"_L1 && *it != "pointCluster"_L1 && *it != "heatmapRenderer"_L1 )
120 {
122 mRendererComboBox->addItem( m->icon(), m->visibleName(), *it );
123 }
124 }
125
126 mCircleColorButton->setColorDialogTitle( tr( "Select Color" ) );
127 mCircleColorButton->setContext( u"symbology"_s );
128 mCircleColorButton->setAllowOpacity( true );
129 mCircleColorButton->setShowNoColor( true );
130 mCircleColorButton->setNoColorString( tr( "Transparent Stroke" ) );
131 mLabelColorButton->setContext( u"symbology"_s );
132 mLabelColorButton->setColorDialogTitle( tr( "Select Color" ) );
133 mLabelColorButton->setAllowOpacity( true );
134
135 mCircleWidthSpinBox->setValue( mRenderer->circleWidth() );
136 mCircleColorButton->setColor( mRenderer->circleColor() );
137 mLabelColorButton->setColor( mRenderer->labelColor() );
138 mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
139 mCircleModificationSpinBox->setClearValue( 0.0 );
140 mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
141 mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
142 mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
143 mDistanceSpinBox->setValue( mRenderer->tolerance() );
144 mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
145 mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
146 mCenterSymbolToolButton->setSymbol( mRenderer->centerSymbol()->clone() );
147
148 mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( mRenderer->placement() ) );
149
150 //scale dependent labeling
151 mMinLabelScaleWidget->setScale( std::max( mRenderer->minimumLabelScale(), 0.0 ) );
152 if ( mRenderer->minimumLabelScale() > 0 )
153 {
154 mScaleDependentLabelsCheckBox->setCheckState( Qt::Checked );
155 }
156 else
157 {
158 mScaleDependentLabelsCheckBox->setCheckState( Qt::Unchecked );
159 mMinLabelScaleWidget->setEnabled( false );
160 }
161
162
163 blockAllSignals( false );
164
165 //set the appropriate renderer dialog
166 if ( mRenderer->embeddedRenderer() )
167 {
168 const QString rendererName = mRenderer->embeddedRenderer()->type();
169 const int rendererIndex = mRendererComboBox->findData( rendererName );
170 if ( rendererIndex != -1 )
171 {
172 mRendererComboBox->setCurrentIndex( rendererIndex );
173 mRendererComboBox_currentIndexChanged( rendererIndex );
174 }
175 }
176
177 connect( mMinLabelScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsPointDisplacementRendererWidget::minLabelScaleChanged );
178 connect( mLabelFontButton, &QgsFontButton::changed, this, &QgsPointDisplacementRendererWidget::labelFontChanged );
179 connect( mCenterSymbolToolButton, &QgsSymbolButton::changed, this, &QgsPointDisplacementRendererWidget::centerSymbolChanged );
180 mCenterSymbolToolButton->setDialogTitle( tr( "Center symbol" ) );
181 mCenterSymbolToolButton->setLayer( mLayer );
182 mCenterSymbolToolButton->registerExpressionContextGenerator( this );
183}
184
186
191
193{
195 if ( mDistanceUnitWidget )
196 mDistanceUnitWidget->setMapCanvas( context.mapCanvas() );
197 if ( mMinLabelScaleWidget )
198 {
199 mMinLabelScaleWidget->setMapCanvas( context.mapCanvas() );
200 mMinLabelScaleWidget->setShowCurrentScaleButton( true );
201 }
202 if ( mCenterSymbolToolButton )
203 {
204 mCenterSymbolToolButton->setMapCanvas( context.mapCanvas() );
205 mCenterSymbolToolButton->setMessageBar( context.messageBar() );
206 }
207}
208
210{
212 if ( auto *lExpressionContext = mContext.expressionContext() )
213 context = *lExpressionContext;
214 else
215 context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
219 QList<QgsExpressionContextScope> scopes = mContext.additionalExpressionContextScopes();
220 scopes << scope;
221 for ( const QgsExpressionContextScope &s : std::as_const( scopes ) )
222 {
224 }
225 return context;
226}
227
228void QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged( const QString &text )
229{
230 if ( mRenderer )
231 {
232 if ( text == tr( "None" ) )
233 {
234 mRenderer->setLabelAttributeName( QString() );
235 }
236 else
237 {
238 mRenderer->setLabelAttributeName( text );
239 }
240 emit widgetChanged();
241 }
242}
243
244void QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged( int index )
245{
246 const QString rendererId = mRendererComboBox->itemData( index ).toString();
247 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( rendererId );
248 if ( m )
249 {
250 // unfortunately renderer conversion is only available through the creation of a widget...
251 const std::unique_ptr<QgsFeatureRenderer> oldRenderer( mRenderer->embeddedRenderer()->clone() );
252 QgsRendererWidget *tempRenderWidget = m->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
253 mRenderer->setEmbeddedRenderer( tempRenderWidget->renderer()->clone() );
254 delete tempRenderWidget;
255 emit widgetChanged();
256 }
257}
258
259void QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged( int index )
260{
261 if ( !mRenderer )
262 return;
263
264 mRenderer->setPlacement( ( QgsPointDisplacementRenderer::Placement ) mPlacementComboBox->itemData( index ).toInt() );
265 emit widgetChanged();
266}
267
268void QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked()
269{
270 if ( !mRenderer )
271 return;
272
273 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
274 if ( m )
275 {
276 QgsRendererWidget *w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
277 w->setPanelTitle( tr( "Renderer Settings" ) );
278
279 QgsSymbolWidgetContext context = mContext;
280
281 QgsExpressionContextScope scope;
282 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
283 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
284 QList<QgsExpressionContextScope> scopes = context.additionalExpressionContextScopes();
285 scopes << scope;
286 context.setAdditionalExpressionContextScopes( scopes );
288 w->setContext( context );
289
290 connect( w, &QgsPanelWidget::widgetChanged, this, &QgsPointDisplacementRendererWidget::updateRendererFromWidget );
291 openPanel( w );
292 }
293}
294
295void QgsPointDisplacementRendererWidget::labelFontChanged()
296{
297 if ( !mRenderer )
298 {
299 return;
300 }
301
302 mRenderer->setLabelFont( mLabelFontButton->currentFont() );
303 emit widgetChanged();
304}
305
306void QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged( double d )
307{
308 if ( mRenderer )
309 {
310 mRenderer->setCircleWidth( d );
311 emit widgetChanged();
312 }
313}
314
315void QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged( const QColor &newColor )
316{
317 if ( !mRenderer )
318 {
319 return;
320 }
321
322 mRenderer->setCircleColor( newColor );
323 emit widgetChanged();
324}
325
326void QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged( const QColor &newColor )
327{
328 if ( !mRenderer )
329 {
330 return;
331 }
332
333 mRenderer->setLabelColor( newColor );
334 emit widgetChanged();
335}
336
337void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged( double d )
338{
339 if ( !mRenderer )
340 {
341 return;
342 }
343
344 mRenderer->setCircleRadiusAddition( d );
345 emit widgetChanged();
346}
347
348void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
349{
350 if ( !mRenderer )
351 {
352 return;
353 }
354
355 mRenderer->setLabelDistanceFactor( d );
356 emit widgetChanged();
357}
358
359void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
360{
361 if ( mRenderer )
362 {
363 mRenderer->setTolerance( d );
364 emit widgetChanged();
365 }
366}
367
368void QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed()
369{
370 if ( mRenderer )
371 {
372 mRenderer->setToleranceUnit( mDistanceUnitWidget->unit() );
373 mRenderer->setToleranceMapUnitScale( mDistanceUnitWidget->getMapUnitScale() );
374 emit widgetChanged();
375 }
376}
377
378void QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged( int state )
379{
380 if ( state == Qt::Unchecked )
381 {
382 mMinLabelScaleWidget->setScale( 0 );
383 mMinLabelScaleWidget->setEnabled( false );
384 }
385 else
386 {
387 mMinLabelScaleWidget->setEnabled( true );
388 }
389}
390
391void QgsPointDisplacementRendererWidget::minLabelScaleChanged( double scale )
392{
393 if ( !mRenderer )
394 {
395 return;
396 }
397
398 mRenderer->setMinimumLabelScale( scale );
399 emit widgetChanged();
400}
401
402void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
403{
404 mLabelFieldComboBox->blockSignals( block );
405 mLabelFontButton->blockSignals( block );
406 mCircleWidthSpinBox->blockSignals( block );
407 mCircleColorButton->blockSignals( block );
408 mRendererComboBox->blockSignals( block );
409 mLabelColorButton->blockSignals( block );
410 mCircleModificationSpinBox->blockSignals( block );
411 mLabelDistanceFactorSpinBox->blockSignals( block );
412 mScaleDependentLabelsCheckBox->blockSignals( block );
413 mMinLabelScaleWidget->blockSignals( block );
414 mCenterSymbolToolButton->blockSignals( block );
415 mDistanceSpinBox->blockSignals( block );
416 mDistanceUnitWidget->blockSignals( block );
417 mPlacementComboBox->blockSignals( block );
418}
419
420void QgsPointDisplacementRendererWidget::centerSymbolChanged()
421{
422 mRenderer->setCenterSymbol( mCenterSymbolToolButton->clonedSymbol<QgsMarkerSymbol>() );
423 emit widgetChanged();
424}
425
426void QgsPointDisplacementRendererWidget::updateRendererFromWidget()
427{
428 QgsRendererWidget *w = qobject_cast<QgsRendererWidget *>( sender() );
429 if ( !w )
430 return;
431
432 mRenderer->setEmbeddedRenderer( w->renderer()->clone() );
433 emit widgetChanged();
434}
435
436void QgsPointDisplacementRendererWidget::setupBlankUi( const QString &layerName )
437{
438 QLabel *label = new QLabel( tr( "The point displacement renderer only applies to (single) point layers. \n'%1' is not a (single) point layer and cannot be displayed by the point displacement renderer." ).arg( layerName ), this );
439 QVBoxLayout *layout = new QVBoxLayout( this );
440 layout->setContentsMargins( 0, 0, 0, 0 );
441 layout->addWidget( label );
442}
@ Point
Points.
Definition qgis.h:366
@ Millimeters
Millimeters.
Definition qgis.h:5256
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5260
@ MapUnits
Map units.
Definition qgis.h:5257
@ Pixels
Pixels.
Definition qgis.h:5258
@ Inches
Inches.
Definition qgis.h:5261
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5263
@ Marker
Marker symbol.
Definition qgis.h:630
static QgsRendererRegistry * rendererRegistry()
Returns the application's renderer registry, used for managing vector layer renderers.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static const QString EXPR_CLUSTER_SIZE
Inbuilt variable name for cluster size variable.
static const QString EXPR_CLUSTER_COLOR
Inbuilt variable name for cluster color variable.
Abstract base class for all 2D vector feature renderers.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
Container of fields for a vector layer.
Definition qgsfields.h:46
@ ModeQFont
Configure font settings for use with QFont objects.
void changed()
Emitted when the widget's text format settings are changed.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void widgetChanged()
Emitted when the widget state changes.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
QgsFeatureRenderer * renderer() override
Returns pointer to the renderer (no transfer of ownership).
void setContext(const QgsSymbolWidgetContext &context) override
Sets the context in which the renderer widget is shown, e.g., the associated map canvas and expressio...
QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Placement
Placement methods for dispersing points.
@ ConcentricRings
Place points in concentric rings around group.
@ Ring
Place points in a single ring around group.
@ Grid
Place points in a grid around group.
static QgsPointDisplacementRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointDisplacementRenderer from an existing renderer.
Stores metadata about one renderer class.
@ PointLayer
Compatible with point layers.
QIcon icon() const
Returns an icon representing the renderer.
QString visibleName() const
Returns a friendly display name of the renderer.
virtual QgsRendererWidget * createRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *oldRenderer)
Returns new instance of settings widget for the renderer.
QStringList renderersList(QgsRendererAbstractMetadata::LayerTypes layerTypes=QgsRendererAbstractMetadata::All) const
Returns a list of available renderers.
QgsRendererAbstractMetadata * rendererMetadata(const QString &rendererName)
Returns the metadata for a specified renderer.
QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)
QgsSymbolWidgetContext mContext
Context in which widget is shown.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the renderer widget is shown, e.g., the associated map canvas and expressio...
virtual QgsFeatureRenderer * renderer()=0
Returns pointer to the renderer (no transfer of ownership).
virtual void disableSymbolLevels()
Disables symbol level modification on the widget.
QgsSymbolWidgetContext context() const
Returns the context in which the renderer widget is shown, e.g., the associated map canvas and expres...
QgsVectorLayer * mLayer
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:89
void changed()
Emitted when the symbol's settings are changed.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::WkbType wkbType() const final
Returns the WKBType or WKBUnknown in case of error.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Single variable definition for use within a QgsExpressionContextScope.