QGIS API Documentation  3.20.0-Odense (decaadbb31)
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 
20 #include "qgsrendererregistry.h"
21 #include "qgsfields.h"
22 #include "qgsstyle.h"
24 #include "qgssymbollayerutils.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsguiutils.h"
27 #include "qgsapplication.h"
28 #include "qgsmarkersymbol.h"
29 
31 {
32  return new QgsPointDisplacementRendererWidget( layer, style, renderer );
33 }
34 
36  : QgsRendererWidget( layer, style )
37 
38 {
39  if ( !layer )
40  {
41  return;
42  }
43 
44  //the renderer only applies to point vector layers
46  {
47  //setup blank dialog
48  mRenderer = nullptr;
49  setupBlankUi( layer->name() );
50  return;
51  }
52  setupUi( this );
53  connect( mLabelFieldComboBox, &QComboBox::currentTextChanged, this, &QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged );
54  connect( mRendererComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged );
55  connect( mPlacementComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged );
56  connect( mCircleWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged );
57  connect( mCircleColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged );
58  connect( mDistanceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged );
59  connect( mDistanceUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed );
60  connect( mLabelColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged );
61  connect( mCircleModificationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged );
62  connect( mLabelDistanceFactorSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged );
63  connect( mScaleDependentLabelsCheckBox, &QCheckBox::stateChanged, this, &QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged );
64  connect( mRendererSettingsButton, &QPushButton::clicked, this, &QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked );
65  this->layout()->setContentsMargins( 0, 0, 0, 0 );
66 
67  mLabelFontButton->setMode( QgsFontButton::ModeQFont );
70  mCenterSymbolToolButton->setSymbolType( Qgis::SymbolType::Marker );
71 
72  if ( renderer )
73  {
75  }
76  if ( !mRenderer )
77  {
78  mRenderer = std::make_unique< QgsPointDisplacementRenderer >();
79  }
80 
81  blockAllSignals( true );
82 
83  mPlacementComboBox->addItem( tr( "Ring" ), QgsPointDisplacementRenderer::Ring );
84  mPlacementComboBox->addItem( tr( "Concentric Rings" ), QgsPointDisplacementRenderer::ConcentricRings );
85  mPlacementComboBox->addItem( tr( "Grid" ), QgsPointDisplacementRenderer::Grid );
86 
87  //insert attributes into combo box
88  if ( layer )
89  {
90  const QgsFields layerFields = layer->fields();
91  for ( const QgsField &f : layerFields )
92  {
93  mLabelFieldComboBox->addItem( f.name() );
94  }
95  mLabelFieldComboBox->addItem( tr( "None" ) );
96 
97  QString currentLabelAttribute = mRenderer->labelAttributeName();
98  if ( !currentLabelAttribute.isEmpty() )
99  {
100  mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( currentLabelAttribute ) );
101  }
102  else
103  {
104  mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( tr( "None" ) ) );
105  }
106  }
107 
108  //insert possible renderer types
110  QStringList::const_iterator it = rendererList.constBegin();
111  for ( ; it != rendererList.constEnd(); ++it )
112  {
113  if ( *it != QLatin1String( "pointDisplacement" ) && *it != QLatin1String( "pointCluster" ) && *it != QLatin1String( "heatmapRenderer" ) )
114  {
116  mRendererComboBox->addItem( m->icon(), m->visibleName(), *it );
117  }
118  }
119 
120  mCircleColorButton->setColorDialogTitle( tr( "Select Color" ) );
121  mCircleColorButton->setContext( QStringLiteral( "symbology" ) );
122  mCircleColorButton->setAllowOpacity( true );
123  mCircleColorButton->setShowNoColor( true );
124  mCircleColorButton->setNoColorString( tr( "Transparent Stroke" ) );
125  mLabelColorButton->setContext( QStringLiteral( "symbology" ) );
126  mLabelColorButton->setColorDialogTitle( tr( "Select Color" ) );
127  mLabelColorButton->setAllowOpacity( true );
128 
129  mCircleWidthSpinBox->setValue( mRenderer->circleWidth() );
130  mCircleColorButton->setColor( mRenderer->circleColor() );
131  mLabelColorButton->setColor( mRenderer->labelColor() );
132  mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
133  mCircleModificationSpinBox->setClearValue( 0.0 );
134  mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
135  mLabelDistanceFactorSpinBox->setClearValue( 0.5 );
136  mLabelDistanceFactorSpinBox->setValue( mRenderer->labelDistanceFactor() );
137  mDistanceSpinBox->setValue( mRenderer->tolerance() );
138  mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
139  mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
140  mCenterSymbolToolButton->setSymbol( mRenderer->centerSymbol()->clone() );
141 
142  mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( mRenderer->placement() ) );
143 
144  //scale dependent labeling
145  mMinLabelScaleWidget->setScale( std::max( mRenderer->minimumLabelScale(), 0.0 ) );
146  if ( mRenderer->minimumLabelScale() > 0 )
147  {
148  mScaleDependentLabelsCheckBox->setCheckState( Qt::Checked );
149  }
150  else
151  {
152  mScaleDependentLabelsCheckBox->setCheckState( Qt::Unchecked );
153  mMinLabelScaleWidget->setEnabled( false );
154  }
155 
156 
157  blockAllSignals( false );
158 
159  //set the appropriate renderer dialog
160  if ( mRenderer->embeddedRenderer() )
161  {
162  QString rendererName = mRenderer->embeddedRenderer()->type();
163  int rendererIndex = mRendererComboBox->findData( rendererName );
164  if ( rendererIndex != -1 )
165  {
166  mRendererComboBox->setCurrentIndex( rendererIndex );
167  mRendererComboBox_currentIndexChanged( rendererIndex );
168  }
169  }
170 
171  connect( mMinLabelScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsPointDisplacementRendererWidget::minLabelScaleChanged );
172  connect( mLabelFontButton, &QgsFontButton::changed, this, &QgsPointDisplacementRendererWidget::labelFontChanged );
173  connect( mCenterSymbolToolButton, &QgsSymbolButton::changed, this, &QgsPointDisplacementRendererWidget::centerSymbolChanged );
174  mCenterSymbolToolButton->setDialogTitle( tr( "Center symbol" ) );
175  mCenterSymbolToolButton->setLayer( mLayer );
176  mCenterSymbolToolButton->registerExpressionContextGenerator( this );
177 }
178 
180 
182 {
183  return mRenderer.get();
184 }
185 
187 {
189  if ( mDistanceUnitWidget )
190  mDistanceUnitWidget->setMapCanvas( context.mapCanvas() );
191  if ( mMinLabelScaleWidget )
192  {
193  mMinLabelScaleWidget->setMapCanvas( context.mapCanvas() );
194  mMinLabelScaleWidget->setShowCurrentScaleButton( true );
195  }
196  if ( mCenterSymbolToolButton )
197  {
198  mCenterSymbolToolButton->setMapCanvas( context.mapCanvas() );
199  mCenterSymbolToolButton->setMessageBar( context.messageBar() );
200  }
201 }
202 
204 {
206  if ( auto *lExpressionContext = mContext.expressionContext() )
207  context = *lExpressionContext;
208  else
213  QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
214  scopes << scope;
215  const auto constScopes = scopes;
216  for ( const QgsExpressionContextScope &s : constScopes )
217  {
219  }
220  return context;
221 }
222 
223 void QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged( const QString &text )
224 {
225  if ( mRenderer )
226  {
227  if ( text == tr( "None" ) )
228  {
229  mRenderer->setLabelAttributeName( QString() );
230  }
231  else
232  {
233  mRenderer->setLabelAttributeName( text );
234  }
235  emit widgetChanged();
236  }
237 }
238 
239 void QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged( int index )
240 {
241  QString rendererId = mRendererComboBox->itemData( index ).toString();
243  if ( m )
244  {
245  // unfortunately renderer conversion is only available through the creation of a widget...
246  std::unique_ptr< QgsFeatureRenderer> oldRenderer( mRenderer->embeddedRenderer()->clone() );
247  QgsRendererWidget *tempRenderWidget = m->createRendererWidget( mLayer, mStyle, oldRenderer.get() );
248  mRenderer->setEmbeddedRenderer( tempRenderWidget->renderer()->clone() );
249  delete tempRenderWidget;
250  emit widgetChanged();
251  }
252 }
253 
254 void QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged( int index )
255 {
256  if ( !mRenderer )
257  return;
258 
259  mRenderer->setPlacement( ( QgsPointDisplacementRenderer::Placement )mPlacementComboBox->itemData( index ).toInt() );
260  emit widgetChanged();
261 }
262 
263 void QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked()
264 {
265  if ( !mRenderer )
266  return;
267 
268  QgsRendererAbstractMetadata *m = QgsApplication::rendererRegistry()->rendererMetadata( mRenderer->embeddedRenderer()->type() );
269  if ( m )
270  {
271  QgsRendererWidget *w = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
272  w->setPanelTitle( tr( "Renderer Settings" ) );
273 
275 
279  QList< QgsExpressionContextScope > scopes = context.additionalExpressionContextScopes();
280  scopes << scope;
282  w->disableSymbolLevels();
283  w->setContext( context );
284 
285  connect( w, &QgsPanelWidget::widgetChanged, this, &QgsPointDisplacementRendererWidget::updateRendererFromWidget );
286  openPanel( w );
287  }
288 }
289 
290 void QgsPointDisplacementRendererWidget::labelFontChanged()
291 {
292  if ( !mRenderer )
293  {
294  return;
295  }
296 
297  mRenderer->setLabelFont( mLabelFontButton->currentFont() );
298  emit widgetChanged();
299 }
300 
301 void QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged( double d )
302 {
303  if ( mRenderer )
304  {
305  mRenderer->setCircleWidth( d );
306  emit widgetChanged();
307  }
308 }
309 
310 void QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged( const QColor &newColor )
311 {
312  if ( !mRenderer )
313  {
314  return;
315  }
316 
317  mRenderer->setCircleColor( newColor );
318  emit widgetChanged();
319 }
320 
321 void QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged( const QColor &newColor )
322 {
323  if ( !mRenderer )
324  {
325  return;
326  }
327 
328  mRenderer->setLabelColor( newColor );
329  emit widgetChanged();
330 }
331 
332 void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged( double d )
333 {
334  if ( !mRenderer )
335  {
336  return;
337  }
338 
339  mRenderer->setCircleRadiusAddition( d );
340  emit widgetChanged();
341 }
342 
343 void QgsPointDisplacementRendererWidget::mLabelDistanceFactorSpinBox_valueChanged( double d )
344 {
345  if ( !mRenderer )
346  {
347  return;
348  }
349 
350  mRenderer->setLabelDistanceFactor( d );
351  emit widgetChanged();
352 }
353 
354 void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
355 {
356  if ( mRenderer )
357  {
358  mRenderer->setTolerance( d );
359  emit widgetChanged();
360  }
361 }
362 
363 void QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed()
364 {
365  if ( mRenderer )
366  {
367  mRenderer->setToleranceUnit( mDistanceUnitWidget->unit() );
368  mRenderer->setToleranceMapUnitScale( mDistanceUnitWidget->getMapUnitScale() );
369  emit widgetChanged();
370  }
371 }
372 
373 void QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged( int state )
374 {
375  if ( state == Qt::Unchecked )
376  {
377  mMinLabelScaleWidget->setScale( 0 );
378  mMinLabelScaleWidget->setEnabled( false );
379  }
380  else
381  {
382  mMinLabelScaleWidget->setEnabled( true );
383  }
384 }
385 
386 void QgsPointDisplacementRendererWidget::minLabelScaleChanged( double scale )
387 {
388  if ( !mRenderer )
389  {
390  return;
391  }
392 
393  mRenderer->setMinimumLabelScale( scale );
394  emit widgetChanged();
395 }
396 
397 void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
398 {
399  mLabelFieldComboBox->blockSignals( block );
400  mLabelFontButton->blockSignals( block );
401  mCircleWidthSpinBox->blockSignals( block );
402  mCircleColorButton->blockSignals( block );
403  mRendererComboBox->blockSignals( block );
404  mLabelColorButton->blockSignals( block );
405  mCircleModificationSpinBox->blockSignals( block );
406  mLabelDistanceFactorSpinBox->blockSignals( block );
407  mScaleDependentLabelsCheckBox->blockSignals( block );
408  mMinLabelScaleWidget->blockSignals( block );
409  mCenterSymbolToolButton->blockSignals( block );
410  mDistanceSpinBox->blockSignals( block );
411  mDistanceUnitWidget->blockSignals( block );
412  mPlacementComboBox->blockSignals( block );
413 }
414 
415 void QgsPointDisplacementRendererWidget::centerSymbolChanged()
416 {
417  mRenderer->setCenterSymbol( mCenterSymbolToolButton->clonedSymbol< QgsMarkerSymbol >() );
418  emit widgetChanged();
419 }
420 
421 void QgsPointDisplacementRendererWidget::updateRendererFromWidget()
422 {
423  QgsRendererWidget *w = qobject_cast<QgsRendererWidget *>( sender() );
424  if ( !w )
425  return;
426 
427  mRenderer->setEmbeddedRenderer( w->renderer()->clone() );
428  emit widgetChanged();
429 }
430 
431 void QgsPointDisplacementRendererWidget::setupBlankUi( const QString &layerName )
432 {
433  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 );
434  QVBoxLayout *layout = new QVBoxLayout( this );
435  layout->setContentsMargins( 0, 0, 0, 0 );
436  layout->addWidget( label );
437 }
@ Marker
Marker symbol.
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.
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:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
@ ModeQFont
Configure font settings for use with QFont objects.
Definition: qgsfontbutton.h:62
void changed()
Emitted when the widget's text format settings are changed.
QString name
Definition: qgsmaplayer.h:73
A marker symbol type, for rendering Point and MultiPoint geometries.
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.
virtual QgsRendererWidget * createRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *oldRenderer)
Returns new instance of settings widget for the renderer.
QString visibleName() const
Returns a friendly display name of 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.
Base class for renderer settings widgets.
virtual QgsFeatureRenderer * renderer()=0
Returns pointer to the renderer (no transfer of ownership)
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 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.
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,...
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer.
QList< QgsExpressionContextScope * > globalProjectAtlasMapLayerScopes(const QgsMapLayer *layer) const
Returns list of scopes: global, project, atlas, map, layer.
void setAdditionalExpressionContextScopes(const QList< QgsExpressionContextScope > &scopes)
Sets a list of additional expression context scopes to show as available within the layer.
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:240
@ RenderMetersInMapUnits
Meters value as Map units.
Definition: qgsunittypes.h:176
@ RenderPoints
Points (e.g., for font sizes)
Definition: qgsunittypes.h:173
@ RenderPixels
Pixels.
Definition: qgsunittypes.h:171
@ RenderInches
Inches.
Definition: qgsunittypes.h:174
@ RenderMillimeters
Millimeters.
Definition: qgsunittypes.h:169
@ RenderMapUnits
Map units.
Definition: qgsunittypes.h:170
Represents a vector layer which manages a vector based data sets.
Q_INVOKABLE QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:938
static bool isMultiType(Type type) SIP_HOLDGIL
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:832
Single variable definition for use within a QgsExpressionContextScope.