QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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 mLabelColorButton->setContext( u"symbology"_s );
134 mLabelColorButton->setColorDialogTitle( tr( "Select Color" ) );
135 mLabelColorButton->setAllowOpacity( true );
136
137 mCircleWidthSpinBox->setValue( mRenderer->circleWidth() );
138 mCircleColorButton->setColor( mRenderer->circleColor() );
139 mLabelColorButton->setColor( mRenderer->labelColor() );
140 mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
141 mCircleModificationSpinBox->setClearValue( 0.0 );
142 mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
143 mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
144 mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
145 mDistanceSpinBox->setValue( mRenderer->tolerance() );
146 mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
147 mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
148 mCenterSymbolToolButton->setSymbol( mRenderer->centerSymbol()->clone() );
149
150 mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( mRenderer->placement() ) );
151
152 //scale dependent labeling
153 mMinLabelScaleWidget->setScale( std::max( mRenderer->minimumLabelScale(), 0.0 ) );
154 if ( mRenderer->minimumLabelScale() > 0 )
155 {
156 mScaleDependentLabelsCheckBox->setCheckState( Qt::Checked );
157 }
158 else
159 {
160 mScaleDependentLabelsCheckBox->setCheckState( Qt::Unchecked );
161 mMinLabelScaleWidget->setEnabled( false );
162 }
163
164
165 blockAllSignals( false );
166
167 //set the appropriate renderer dialog
168 if ( mRenderer->embeddedRenderer() )
169 {
170 const QString rendererName = mRenderer->embeddedRenderer()->type();
171 const int rendererIndex = mRendererComboBox->findData( rendererName );
172 if ( rendererIndex != -1 )
173 {
174 mRendererComboBox->setCurrentIndex( rendererIndex );
175 mRendererComboBox_currentIndexChanged( rendererIndex );
176 }
177 }
178
179 connect( mMinLabelScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsPointDisplacementRendererWidget::minLabelScaleChanged );
180 connect( mLabelFontButton, &QgsFontButton::changed, this, &QgsPointDisplacementRendererWidget::labelFontChanged );
181 connect( mCenterSymbolToolButton, &QgsSymbolButton::changed, this, &QgsPointDisplacementRendererWidget::centerSymbolChanged );
182 mCenterSymbolToolButton->setDialogTitle( tr( "Center symbol" ) );
183 mCenterSymbolToolButton->setLayer( mLayer );
184 mCenterSymbolToolButton->registerExpressionContextGenerator( this );
185}
186
188
193
195{
197 if ( mDistanceUnitWidget )
198 mDistanceUnitWidget->setMapCanvas( context.mapCanvas() );
199 if ( mMinLabelScaleWidget )
200 {
201 mMinLabelScaleWidget->setMapCanvas( context.mapCanvas() );
202 mMinLabelScaleWidget->setShowCurrentScaleButton( true );
203 }
204 if ( mCenterSymbolToolButton )
205 {
206 mCenterSymbolToolButton->setMapCanvas( context.mapCanvas() );
207 mCenterSymbolToolButton->setMessageBar( context.messageBar() );
208 }
209}
210
212{
214 if ( auto *lExpressionContext = mContext.expressionContext() )
215 context = *lExpressionContext;
216 else
217 context.appendScopes( mContext.globalProjectAtlasMapLayerScopes( mLayer ) );
221 QList<QgsExpressionContextScope> scopes = mContext.additionalExpressionContextScopes();
222 scopes << scope;
223 for ( const QgsExpressionContextScope &s : std::as_const( scopes ) )
224 {
226 }
227 return context;
228}
229
230void QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged( const QString &text )
231{
232 if ( mRenderer )
233 {
234 if ( text == tr( "None" ) )
235 {
236 mRenderer->setLabelAttributeName( QString() );
237 }
238 else
239 {
240 mRenderer->setLabelAttributeName( text );
241 }
242 emit widgetChanged();
243 }
244}
245
246void QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged( int index )
247{
248 const QString rendererId = mRendererComboBox->itemData( index ).toString();
249 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( rendererId );
250 if ( m )
251 {
252 // unfortunately renderer conversion is only available through the creation of a widget...
253 const std::unique_ptr<QgsFeatureRenderer> oldRenderer( mRenderer->embeddedRenderer()->clone() );
254 QgsRendererWidget *tempRenderWidget = m->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
255 mRenderer->setEmbeddedRenderer( tempRenderWidget->renderer()->clone() );
256 delete tempRenderWidget;
257 emit widgetChanged();
258 }
259}
260
261void QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged( int index )
262{
263 if ( !mRenderer )
264 return;
265
266 mRenderer->setPlacement( ( QgsPointDisplacementRenderer::Placement ) mPlacementComboBox->itemData( index ).toInt() );
267 emit widgetChanged();
268}
269
270void QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked()
271{
272 if ( !mRenderer )
273 return;
274
275 QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
276 if ( m )
277 {
278 QgsRendererWidget *w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
279 w->setPanelTitle( tr( "Renderer Settings" ) );
280
281 QgsSymbolWidgetContext context = mContext;
282
283 QgsExpressionContextScope scope;
284 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_COLOR, "", true ) );
285 scope.addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_CLUSTER_SIZE, 0, true ) );
286 QList<QgsExpressionContextScope> scopes = context.additionalExpressionContextScopes();
287 scopes << scope;
288 context.setAdditionalExpressionContextScopes( scopes );
290 w->setContext( context );
291
292 connect( w, &QgsPanelWidget::widgetChanged, this, &QgsPointDisplacementRendererWidget::updateRendererFromWidget );
293 openPanel( w );
294 }
295}
296
297void QgsPointDisplacementRendererWidget::labelFontChanged()
298{
299 if ( !mRenderer )
300 {
301 return;
302 }
303
304 mRenderer->setLabelFont( mLabelFontButton->currentFont() );
305 emit widgetChanged();
306}
307
308void QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged( double d )
309{
310 if ( mRenderer )
311 {
312 mRenderer->setCircleWidth( d );
313 emit widgetChanged();
314 }
315}
316
317void QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged( const QColor &newColor )
318{
319 if ( !mRenderer )
320 {
321 return;
322 }
323
324 mRenderer->setCircleColor( newColor );
325 emit widgetChanged();
326}
327
328void QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged( const QColor &newColor )
329{
330 if ( !mRenderer )
331 {
332 return;
333 }
334
335 mRenderer->setLabelColor( newColor );
336 emit widgetChanged();
337}
338
339void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged( double d )
340{
341 if ( !mRenderer )
342 {
343 return;
344 }
345
346 mRenderer->setCircleRadiusAddition( d );
347 emit widgetChanged();
348}
349
350void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
351{
352 if ( !mRenderer )
353 {
354 return;
355 }
356
357 mRenderer->setLabelDistanceFactor( d );
358 emit widgetChanged();
359}
360
361void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
362{
363 if ( mRenderer )
364 {
365 mRenderer->setTolerance( d );
366 emit widgetChanged();
367 }
368}
369
370void QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed()
371{
372 if ( mRenderer )
373 {
374 mRenderer->setToleranceUnit( mDistanceUnitWidget->unit() );
375 mRenderer->setToleranceMapUnitScale( mDistanceUnitWidget->getMapUnitScale() );
376 emit widgetChanged();
377 }
378}
379
380void QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged( int state )
381{
382 if ( state == Qt::Unchecked )
383 {
384 mMinLabelScaleWidget->setScale( 0 );
385 mMinLabelScaleWidget->setEnabled( false );
386 }
387 else
388 {
389 mMinLabelScaleWidget->setEnabled( true );
390 }
391}
392
393void QgsPointDisplacementRendererWidget::minLabelScaleChanged( double scale )
394{
395 if ( !mRenderer )
396 {
397 return;
398 }
399
400 mRenderer->setMinimumLabelScale( scale );
401 emit widgetChanged();
402}
403
404void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
405{
406 mLabelFieldComboBox->blockSignals( block );
407 mLabelFontButton->blockSignals( block );
408 mCircleWidthSpinBox->blockSignals( block );
409 mCircleColorButton->blockSignals( block );
410 mRendererComboBox->blockSignals( block );
411 mLabelColorButton->blockSignals( block );
412 mCircleModificationSpinBox->blockSignals( block );
413 mLabelDistanceFactorSpinBox->blockSignals( block );
414 mScaleDependentLabelsCheckBox->blockSignals( block );
415 mMinLabelScaleWidget->blockSignals( block );
416 mCenterSymbolToolButton->blockSignals( block );
417 mDistanceSpinBox->blockSignals( block );
418 mDistanceUnitWidget->blockSignals( block );
419 mPlacementComboBox->blockSignals( block );
420}
421
422void QgsPointDisplacementRendererWidget::centerSymbolChanged()
423{
424 mRenderer->setCenterSymbol( mCenterSymbolToolButton->clonedSymbol<QgsMarkerSymbol>() );
425 emit widgetChanged();
426}
427
428void QgsPointDisplacementRendererWidget::updateRendererFromWidget()
429{
430 QgsRendererWidget *w = qobject_cast<QgsRendererWidget *>( sender() );
431 if ( !w )
432 return;
433
434 mRenderer->setEmbeddedRenderer( w->renderer()->clone() );
435 emit widgetChanged();
436}
437
438void QgsPointDisplacementRendererWidget::setupBlankUi( const QString &layerName )
439{
440 QLabel *label
441 = 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 );
442 QVBoxLayout *layout = new QVBoxLayout( this );
443 layout->setContentsMargins( 0, 0, 0, 0 );
444 layout->addWidget( label );
445}
@ Point
Points.
Definition qgis.h:380
@ Millimeters
Millimeters.
Definition qgis.h:5341
@ Points
Points (e.g., for font sizes).
Definition qgis.h:5345
@ MapUnits
Map units.
Definition qgis.h:5342
@ Pixels
Pixels.
Definition qgis.h:5343
@ Inches
Inches.
Definition qgis.h:5346
@ MetersInMapUnits
Meters value as Map units.
Definition qgis.h:5348
@ Marker
Marker symbol.
Definition qgis.h:637
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.