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