QGIS API Documentation 4.3.0-Master (16649ce5cc6)
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 );
73 mDistanceUnitWidget->setUnits(
75 );
76 mCenterSymbolToolButton->setSymbolType( Qgis::SymbolType::Marker );
77
78 if ( renderer )
79 {
81 }
82 if ( !mRenderer )
83 {
84 mRenderer = std::make_unique<QgsPointDisplacementRenderer>();
85 if ( renderer )
86 renderer->copyRendererData( mRenderer.get() );
87 }
88
89 blockAllSignals( true );
90
91 mPlacementComboBox->addItem( tr( "Ring" ), QgsPointDisplacementRenderer::Ring );
92 mPlacementComboBox->addItem( tr( "Concentric Rings" ), QgsPointDisplacementRenderer::ConcentricRings );
93 mPlacementComboBox->addItem( tr( "Grid" ), QgsPointDisplacementRenderer::Grid );
94
95 //insert attributes into combo box
96 if ( layer )
97 {
98 const QgsFields layerFields = layer->fields();
99 for ( const QgsField &f : layerFields )
100 {
101 mLabelFieldComboBox->addItem( f.name() );
102 }
103 mLabelFieldComboBox->addItem( tr( "None" ) );
104
105 const QString currentLabelAttribute = mRenderer->labelAttributeName();
106 if ( !currentLabelAttribute.isEmpty() )
107 {
108 mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( currentLabelAttribute ) );
109 }
110 else
111 {
112 mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( tr( "None" ) ) );
113 }
114 }
115
116 //insert possible renderer types
118 QStringList::const_iterator it = rendererList.constBegin();
119 for ( ; it != rendererList.constEnd(); ++it )
120 {
121 if ( *it != "pointDisplacement"_L1 && *it != "pointCluster"_L1 && *it != "heatmapRenderer"_L1 )
122 {
124 mRendererComboBox->addItem( m->icon(), m->visibleName(), *it );
125 }
126 }
127
128 mCircleColorButton->setColorDialogTitle( tr( "Select Color" ) );
129 mCircleColorButton->setContext( u"symbology"_s );
130 mCircleColorButton->setAllowOpacity( true );
131 mCircleColorButton->setShowNoColor( true );
132 mCircleColorButton->setNoColorString( tr( "Transparent Stroke" ) );
133 mCircleColorButton->setOpaqueColorString( tr( "Opaque Stroke" ) );
134 mLabelColorButton->setContext( u"symbology"_s );
135 mLabelColorButton->setColorDialogTitle( tr( "Select Color" ) );
136 mLabelColorButton->setAllowOpacity( true );
137
138 mCircleWidthSpinBox->setValue( mRenderer->circleWidth() );
139 mCircleColorButton->setColor( mRenderer->circleColor() );
140 mLabelColorButton->setColor( mRenderer->labelColor() );
141 mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
142 mCircleModificationSpinBox->setClearValue( 0.0 );
143 mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
144 mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
145 mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
146 mDistanceSpinBox->setValue( mRenderer->tolerance() );
147 mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
148 mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
149 mCenterSymbolToolButton->setSymbol( mRenderer->centerSymbol()->clone() );
150
151 mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( mRenderer->placement() ) );
152
153 //scale dependent labeling
154 mMinLabelScaleWidget->setScale( std::max( mRenderer->minimumLabelScale(), 0.0 ) );
155 if ( mRenderer->minimumLabelScale() > 0 )
156 {
157 mScaleDependentLabelsCheckBox->setCheckState( Qt::Checked );
158 }
159 else
160 {
161 mScaleDependentLabelsCheckBox->setCheckState( Qt::Unchecked );
162 mMinLabelScaleWidget->setEnabled( false );
163 }
164
165
166 blockAllSignals( false );
167
168 //set the appropriate renderer dialog
169 if ( mRenderer->embeddedRenderer() )
170 {
171 const QString rendererName = mRenderer->embeddedRenderer()->type();
172 const int rendererIndex = mRendererComboBox->findData( rendererName );
173 if ( rendererIndex != -1 )
174 {
175 mRendererComboBox->setCurrentIndex( rendererIndex );
176 mRendererComboBox_currentIndexChanged( rendererIndex );
177 }
178 }
179
180 connect( mMinLabelScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsPointDisplacementRendererWidget::minLabelScaleChanged );
181 connect( mLabelFontButton, &QgsFontButton::changed, this, &QgsPointDisplacementRendererWidget::labelFontChanged );
182 connect( mCenterSymbolToolButton, &QgsSymbolButton::changed, this, &QgsPointDisplacementRendererWidget::centerSymbolChanged );
183 mCenterSymbolToolButton->setDialogTitle( tr( "Center symbol" ) );
184 mCenterSymbolToolButton->setLayer( mLayer );
185 mCenterSymbolToolButton->registerExpressionContextGenerator( this );
186}
187
189
194
196{
198 if ( mDistanceUnitWidget )
199 mDistanceUnitWidget->setMapCanvas( context.mapCanvas() );
200 if ( mMinLabelScaleWidget )
201 {
202 mMinLabelScaleWidget->setMapCanvas( context.mapCanvas() );
203 mMinLabelScaleWidget->setShowCurrentScaleButton( true );
204 }
205 if ( mCenterSymbolToolButton )
206 {
207 mCenterSymbolToolButton->setMapCanvas( context.mapCanvas() );
208 mCenterSymbolToolButton->setMessageBar( context.messageBar() );
209 }
210}
211
213{
215 if ( auto *lExpressionContext = mContext.expressionContext() )
216 context = *lExpressionContext;
217 else
218 context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
222 QList<QgsExpressionContextScope> scopes = mContext.additionalExpressionContextScopes();
223 scopes << scope;
224 for ( const QgsExpressionContextScope &s : std::as_const( scopes ) )
225 {
227 }
228 return context;
229}
230
231void QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged( const QString &text )
232{
233 if ( mRenderer )
234 {
235 if ( text == tr( "None" ) )
236 {
237 mRenderer->setLabelAttributeName( QString() );
238 }
239 else
240 {
241 mRenderer->setLabelAttributeName( text );
242 }
243 emit changed();
244 }
245}
246
247void QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged( int index )
248{
249 const QString rendererId = mRendererComboBox->itemData( index ).toString();
250 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( rendererId );
251 if ( m )
252 {
253 // unfortunately renderer conversion is only available through the creation of a widget...
254 const std::unique_ptr<QgsFeatureRenderer> oldRenderer( mRenderer->embeddedRenderer()->clone() );
255 QgsRendererWidget *tempRenderWidget = m->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
256 mRenderer->setEmbeddedRenderer( tempRenderWidget->renderer()->clone() );
257 delete tempRenderWidget;
258 emit changed();
259 }
260}
261
262void QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged( int index )
263{
264 if ( !mRenderer )
265 return;
266
267 mRenderer->setPlacement( ( QgsPointDisplacementRenderer::Placement ) mPlacementComboBox->itemData( index ).toInt() );
268 emit changed();
269}
270
271void QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked()
272{
273 if ( !mRenderer )
274 return;
275
276 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
277 if ( m )
278 {
279 QgsRendererWidget *w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
280 w->setPanelTitle( tr( "Renderer Settings" ) );
281
282 QgsSymbolWidgetContext context = mContext;
283
284 QgsExpressionContextScope scope;
285 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
286 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
287 QList<QgsExpressionContextScope> scopes = context.additionalExpressionContextScopes();
288 scopes << scope;
289 context.setAdditionalExpressionContextScopes( scopes );
291 w->setContext( context );
292
293 connect( w, &QgsPanelWidget::changed, this, &QgsPointDisplacementRendererWidget::updateRendererFromWidget );
294 openPanel( w );
295 }
296}
297
298void QgsPointDisplacementRendererWidget::labelFontChanged()
299{
300 if ( !mRenderer )
301 {
302 return;
303 }
304
305 mRenderer->setLabelFont( mLabelFontButton->currentFont() );
306 emit changed();
307}
308
309void QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged( double d )
310{
311 if ( mRenderer )
312 {
313 mRenderer->setCircleWidth( d );
314 emit changed();
315 }
316}
317
318void QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged( const QColor &newColor )
319{
320 if ( !mRenderer )
321 {
322 return;
323 }
324
325 mRenderer->setCircleColor( newColor );
326 emit changed();
327}
328
329void QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged( const QColor &newColor )
330{
331 if ( !mRenderer )
332 {
333 return;
334 }
335
336 mRenderer->setLabelColor( newColor );
337 emit changed();
338}
339
340void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged( double d )
341{
342 if ( !mRenderer )
343 {
344 return;
345 }
346
347 mRenderer->setCircleRadiusAddition( d );
348 emit changed();
349}
350
351void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
352{
353 if ( !mRenderer )
354 {
355 return;
356 }
357
358 mRenderer->setLabelDistanceFactor( d );
359 emit changed();
360}
361
362void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
363{
364 if ( mRenderer )
365 {
366 mRenderer->setTolerance( d );
367 emit changed();
368 }
369}
370
371void QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed()
372{
373 if ( mRenderer )
374 {
375 mRenderer->setToleranceUnit( mDistanceUnitWidget->unit() );
376 mRenderer->setToleranceMapUnitScale( mDistanceUnitWidget->getMapUnitScale() );
377 emit changed();
378 }
379}
380
381void QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged( int state )
382{
383 if ( state == Qt::Unchecked )
384 {
385 mMinLabelScaleWidget->setScale( 0 );
386 mMinLabelScaleWidget->setEnabled( false );
387 }
388 else
389 {
390 mMinLabelScaleWidget->setEnabled( true );
391 }
392}
393
394void QgsPointDisplacementRendererWidget::minLabelScaleChanged( double scale )
395{
396 if ( !mRenderer )
397 {
398 return;
399 }
400
401 mRenderer->setMinimumLabelScale( scale );
402 emit changed();
403}
404
405void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
406{
407 mLabelFieldComboBox->blockSignals( block );
408 mLabelFontButton->blockSignals( block );
409 mCircleWidthSpinBox->blockSignals( block );
410 mCircleColorButton->blockSignals( block );
411 mRendererComboBox->blockSignals( block );
412 mLabelColorButton->blockSignals( block );
413 mCircleModificationSpinBox->blockSignals( block );
414 mLabelDistanceFactorSpinBox->blockSignals( block );
415 mScaleDependentLabelsCheckBox->blockSignals( block );
416 mMinLabelScaleWidget->blockSignals( block );
417 mCenterSymbolToolButton->blockSignals( block );
418 mDistanceSpinBox->blockSignals( block );
419 mDistanceUnitWidget->blockSignals( block );
420 mPlacementComboBox->blockSignals( block );
421}
422
423void QgsPointDisplacementRendererWidget::centerSymbolChanged()
424{
425 mRenderer->setCenterSymbol( mCenterSymbolToolButton->clonedSymbol<QgsMarkerSymbol>() );
426 emit changed();
427}
428
429void QgsPointDisplacementRendererWidget::updateRendererFromWidget()
430{
431 QgsRendererWidget *w = qobject_cast<QgsRendererWidget *>( sender() );
432 if ( !w )
433 return;
434
435 mRenderer->setEmbeddedRenderer( w->renderer()->clone() );
436 emit changed();
437}
438
439void QgsPointDisplacementRendererWidget::setupBlankUi( const QString &layerName )
440{
441 QLabel *label
442 = 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 );
443 QVBoxLayout *layout = new QVBoxLayout( this );
444 layout->setContentsMargins( 0, 0, 0, 0 );
445 layout->addWidget( label );
446}
@ Point
Points.
Definition qgis.h:380
@ Millimeters
Millimeters.
Definition qgis.h:5739
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5743
@ MapUnits
Map units.
Definition qgis.h:5740
@ Pixels
Pixels.
Definition qgis.h:5741
@ Inches
Inches.
Definition qgis.h:5744
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5746
@ Marker
Marker symbol.
Definition qgis.h:652
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:45
@ 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 changed()
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)
static std::unique_ptr< QgsPointDisplacementRenderer > convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointDisplacementRenderer from an existing 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.
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:91
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.