QGIS API Documentation  2.99.0-Master (b058df7)
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 
29 {
30  return new QgsPointDisplacementRendererWidget( layer, style, renderer );
31 }
32 
34  : QgsRendererWidget( layer, style )
35 
36 {
37  if ( !layer )
38  {
39  return;
40  }
41 
42  //the renderer only applies to point vector layers
43  if ( layer->wkbType() != QgsWkbTypes::Point && layer->wkbType() != QgsWkbTypes::Point25D )
44  {
45  //setup blank dialog
46  mRenderer = nullptr;
47  setupBlankUi( layer->name() );
48  return;
49  }
50  setupUi( this );
51  connect( mLabelFieldComboBox, static_cast<void ( QComboBox::* )( const QString & )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged );
52  connect( mRendererComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged );
53  connect( mPlacementComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged );
54  connect( mCircleWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged );
55  connect( mCircleColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged );
56  connect( mDistanceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged );
57  connect( mDistanceUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed );
58  connect( mLabelColorButton, &QgsColorButton::colorChanged, this, &QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged );
59  connect( mCircleModificationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged );
60  connect( mScaleDependentLabelsCheckBox, &QCheckBox::stateChanged, this, &QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged );
61  connect( mRendererSettingsButton, &QPushButton::clicked, this, &QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked );
62  this->layout()->setContentsMargins( 0, 0, 0, 0 );
63 
64  mLabelFontButton->setMode( QgsFontButton::ModeQFont );
67  mCenterSymbolToolButton->setSymbolType( QgsSymbol::Marker );
68 
69  if ( renderer )
70  {
72  }
73  if ( !mRenderer )
74  {
75  mRenderer = new QgsPointDisplacementRenderer();
76  }
77 
78  blockAllSignals( true );
79 
80  mPlacementComboBox->addItem( tr( "Ring" ), QgsPointDisplacementRenderer::Ring );
81  mPlacementComboBox->addItem( tr( "Concentric rings" ), QgsPointDisplacementRenderer::ConcentricRings );
82  mPlacementComboBox->addItem( tr( "Grid" ), QgsPointDisplacementRenderer::Grid );
83 
84  //insert attributes into combo box
85  if ( layer )
86  {
87  const QgsFields layerFields = layer->fields();
88  for ( const QgsField &f : layerFields )
89  {
90  mLabelFieldComboBox->addItem( f.name() );
91  }
92  mLabelFieldComboBox->addItem( tr( "None" ) );
93 
94  QString currentLabelAttribute = mRenderer->labelAttributeName();
95  if ( !currentLabelAttribute.isEmpty() )
96  {
97  mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( currentLabelAttribute ) );
98  }
99  else
100  {
101  mLabelFieldComboBox->setCurrentIndex( mLabelFieldComboBox->findText( tr( "None" ) ) );
102  }
103  }
104 
105  //insert possible renderer types
107  QStringList::const_iterator it = rendererList.constBegin();
108  for ( ; it != rendererList.constEnd(); ++it )
109  {
110  if ( *it != QLatin1String( "pointDisplacement" ) && *it != QLatin1String( "pointCluster" ) && *it != QLatin1String( "heatmapRenderer" ) )
111  {
113  mRendererComboBox->addItem( m->icon(), m->visibleName(), *it );
114  }
115  }
116 
117  mCircleColorButton->setColorDialogTitle( tr( "Select Color" ) );
118  mCircleColorButton->setContext( QStringLiteral( "symbology" ) );
119  mCircleColorButton->setAllowOpacity( true );
120  mCircleColorButton->setShowNoColor( true );
121  mCircleColorButton->setNoColorString( tr( "No stroke" ) );
122  mLabelColorButton->setContext( QStringLiteral( "symbology" ) );
123  mLabelColorButton->setColorDialogTitle( tr( "Select Color" ) );
124  mLabelColorButton->setAllowOpacity( true );
125 
126  mCircleWidthSpinBox->setValue( mRenderer->circleWidth() );
127  mCircleColorButton->setColor( mRenderer->circleColor() );
128  mLabelColorButton->setColor( mRenderer->labelColor() );
129  mLabelFontButton->setCurrentFont( mRenderer->labelFont() );
130  mCircleModificationSpinBox->setClearValue( 0.0 );
131  mCircleModificationSpinBox->setValue( mRenderer->circleRadiusAddition() );
132  mDistanceSpinBox->setValue( mRenderer->tolerance() );
133  mDistanceUnitWidget->setUnit( mRenderer->toleranceUnit() );
134  mDistanceUnitWidget->setMapUnitScale( mRenderer->toleranceMapUnitScale() );
135  mCenterSymbolToolButton->setSymbol( mRenderer->centerSymbol()->clone() );
136 
137  mPlacementComboBox->setCurrentIndex( mPlacementComboBox->findData( mRenderer->placement() ) );
138 
139  //scale dependent labeling
140  mMinLabelScaleWidget->setScale( std::max( mRenderer->minimumLabelScale(), 0.0 ) );
141  if ( mRenderer->minimumLabelScale() > 0 )
142  {
143  mScaleDependentLabelsCheckBox->setCheckState( Qt::Checked );
144  }
145  else
146  {
147  mScaleDependentLabelsCheckBox->setCheckState( Qt::Unchecked );
148  mMinLabelScaleWidget->setEnabled( false );
149  }
150 
151 
152  blockAllSignals( false );
153 
154  //set the appropriate renderer dialog
155  if ( mRenderer->embeddedRenderer() )
156  {
157  QString rendererName = mRenderer->embeddedRenderer()->type();
158  int rendererIndex = mRendererComboBox->findData( rendererName );
159  if ( rendererIndex != -1 )
160  {
161  mRendererComboBox->setCurrentIndex( rendererIndex );
162  mRendererComboBox_currentIndexChanged( rendererIndex );
163  }
164  }
165 
166  connect( mMinLabelScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsPointDisplacementRendererWidget::minLabelScaleChanged );
167  connect( mLabelFontButton, &QgsFontButton::changed, this, &QgsPointDisplacementRendererWidget::labelFontChanged );
168  connect( mCenterSymbolToolButton, &QgsSymbolButton::changed, this, &QgsPointDisplacementRendererWidget::centerSymbolChanged );
169  mCenterSymbolToolButton->setDialogTitle( tr( "Center symbol" ) );
170  mCenterSymbolToolButton->setLayer( mLayer );
171  mCenterSymbolToolButton->registerExpressionContextGenerator( this );
172 }
173 
175 {
176  delete mRenderer;
177 }
178 
180 {
181  return mRenderer;
182 }
183 
185 {
187  if ( mDistanceUnitWidget )
188  mDistanceUnitWidget->setMapCanvas( context.mapCanvas() );
189  if ( mMinLabelScaleWidget )
190  {
191  mMinLabelScaleWidget->setMapCanvas( context.mapCanvas() );
192  mMinLabelScaleWidget->setShowCurrentScaleButton( true );
193  }
194  if ( mCenterSymbolToolButton )
195  {
196  mCenterSymbolToolButton->setMapCanvas( context.mapCanvas() );
197  }
198 }
199 
201 {
203  if ( mContext.expressionContext() )
204  context = *mContext.expressionContext();
205  else
210  QList< QgsExpressionContextScope > scopes = mContext.additionalExpressionContextScopes();
211  scopes << scope;
212  Q_FOREACH ( const QgsExpressionContextScope &s, scopes )
213  {
214  context << new QgsExpressionContextScope( s );
215  }
216  return context;
217 }
218 
219 void QgsPointDisplacementRendererWidget::mLabelFieldComboBox_currentIndexChanged( const QString &text )
220 {
221  if ( mRenderer )
222  {
223  if ( text == tr( "None" ) )
224  {
225  mRenderer->setLabelAttributeName( QLatin1String( "" ) );
226  }
227  else
228  {
229  mRenderer->setLabelAttributeName( text );
230  }
231  emit widgetChanged();
232  }
233 }
234 
235 void QgsPointDisplacementRendererWidget::mRendererComboBox_currentIndexChanged( int index )
236 {
237  QString rendererId = mRendererComboBox->itemData( index ).toString();
239  if ( m )
240  {
241  // unfortunately renderer conversion is only available through the creation of a widget...
242  QgsRendererWidget *tempRenderWidget = m->createRendererWidget( mLayer, mStyle, mRenderer->embeddedRenderer()->clone() );
243  mRenderer->setEmbeddedRenderer( tempRenderWidget->renderer()->clone() );
244  delete tempRenderWidget;
245  emit widgetChanged();
246  }
247 }
248 
249 void QgsPointDisplacementRendererWidget::mPlacementComboBox_currentIndexChanged( int index )
250 {
251  if ( !mRenderer )
252  return;
253 
254  mRenderer->setPlacement( ( QgsPointDisplacementRenderer::Placement )mPlacementComboBox->itemData( index ).toInt() );
255  emit widgetChanged();
256 }
257 
258 void QgsPointDisplacementRendererWidget::mRendererSettingsButton_clicked()
259 {
260  if ( !mRenderer )
261  return;
262 
264  if ( m )
265  {
267  w->setPanelTitle( tr( "Renderer settings" ) );
268 
270 
274  QList< QgsExpressionContextScope > scopes = context.additionalExpressionContextScopes();
275  scopes << scope;
276  context.setAdditionalExpressionContextScopes( scopes );
277  w->setContext( context );
278 
279  connect( w, &QgsPanelWidget::widgetChanged, this, &QgsPointDisplacementRendererWidget::updateRendererFromWidget );
280  openPanel( w );
281  }
282 }
283 
284 void QgsPointDisplacementRendererWidget::labelFontChanged()
285 {
286  if ( !mRenderer )
287  {
288  return;
289  }
290 
291  mRenderer->setLabelFont( mLabelFontButton->currentFont() );
292  emit widgetChanged();
293 }
294 
295 void QgsPointDisplacementRendererWidget::mCircleWidthSpinBox_valueChanged( double d )
296 {
297  if ( mRenderer )
298  {
299  mRenderer->setCircleWidth( d );
300  emit widgetChanged();
301  }
302 }
303 
304 void QgsPointDisplacementRendererWidget::mCircleColorButton_colorChanged( const QColor &newColor )
305 {
306  if ( !mRenderer )
307  {
308  return;
309  }
310 
311  mRenderer->setCircleColor( newColor );
312  emit widgetChanged();
313 }
314 
315 void QgsPointDisplacementRendererWidget::mLabelColorButton_colorChanged( const QColor &newColor )
316 {
317  if ( !mRenderer )
318  {
319  return;
320  }
321 
322  mRenderer->setLabelColor( newColor );
323  emit widgetChanged();
324 }
325 
326 void QgsPointDisplacementRendererWidget::mCircleModificationSpinBox_valueChanged( double d )
327 {
328  if ( !mRenderer )
329  {
330  return;
331  }
332 
333  mRenderer->setCircleRadiusAddition( d );
334  emit widgetChanged();
335 }
336 
337 void QgsPointDisplacementRendererWidget::mDistanceSpinBox_valueChanged( double d )
338 {
339  if ( mRenderer )
340  {
341  mRenderer->setTolerance( d );
342  emit widgetChanged();
343  }
344 }
345 
346 void QgsPointDisplacementRendererWidget::mDistanceUnitWidget_changed()
347 {
348  if ( mRenderer )
349  {
350  mRenderer->setToleranceUnit( mDistanceUnitWidget->unit() );
351  mRenderer->setToleranceMapUnitScale( mDistanceUnitWidget->getMapUnitScale() );
352  emit widgetChanged();
353  }
354 }
355 
356 void QgsPointDisplacementRendererWidget::mScaleDependentLabelsCheckBox_stateChanged( int state )
357 {
358  if ( state == Qt::Unchecked )
359  {
360  mMinLabelScaleWidget->setScale( 0 );
361  mMinLabelScaleWidget->setEnabled( false );
362  }
363  else
364  {
365  mMinLabelScaleWidget->setEnabled( true );
366  }
367 }
368 
369 void QgsPointDisplacementRendererWidget::minLabelScaleChanged( double scale )
370 {
371  if ( !mRenderer )
372  {
373  return;
374  }
375 
376  mRenderer->setMinimumLabelScale( scale );
377  emit widgetChanged();
378 }
379 
380 void QgsPointDisplacementRendererWidget::blockAllSignals( bool block )
381 {
382  mLabelFieldComboBox->blockSignals( block );
383  mLabelFontButton->blockSignals( block );
384  mCircleWidthSpinBox->blockSignals( block );
385  mCircleColorButton->blockSignals( block );
386  mRendererComboBox->blockSignals( block );
387  mLabelColorButton->blockSignals( block );
388  mCircleModificationSpinBox->blockSignals( block );
389  mScaleDependentLabelsCheckBox->blockSignals( block );
390  mMinLabelScaleWidget->blockSignals( block );
391  mCenterSymbolToolButton->blockSignals( block );
392  mDistanceSpinBox->blockSignals( block );
393  mDistanceUnitWidget->blockSignals( block );
394  mPlacementComboBox->blockSignals( block );
395 }
396 
397 void QgsPointDisplacementRendererWidget::centerSymbolChanged()
398 {
399  mRenderer->setCenterSymbol( mCenterSymbolToolButton->clonedSymbol< QgsMarkerSymbol >() );
400  emit widgetChanged();
401 }
402 
403 void QgsPointDisplacementRendererWidget::updateRendererFromWidget()
404 {
405  QgsRendererWidget *w = qobject_cast<QgsRendererWidget *>( sender() );
406  if ( !w )
407  return;
408 
409  mRenderer->setEmbeddedRenderer( w->renderer()->clone() );
410  emit widgetChanged();
411 }
412 
413 void QgsPointDisplacementRendererWidget::setupBlankUi( const QString &layerName )
414 {
415  QLabel *label = new QLabel( tr( "The point displacement renderer only applies to (single) point layers. \n'%1' is not a point layer and cannot be displayed by the point displacement renderer" ).arg( layerName ), this );
416  QVBoxLayout *layout = new QVBoxLayout( this );
417  layout->setContentsMargins( 0, 0, 0, 0 );
418  layout->addWidget( label );
419 }
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static const QString EXPR_CLUSTER_COLOR
Inbuilt variable name for cluster color variable.
Meters value as Map units.
Definition: qgsunittypes.h:109
Single variable definition for use within a QgsExpressionContextScope.
QList< QgsExpressionContextScope * > globalProjectAtlasMapLayerScopes(const QgsMapLayer *layer) const
Returns list of scopes: global, project, atlas, map, layer.
Placement
Placement methods for dispersing points.
Place points in a grid around group.
virtual QgsFeatureRenderer * renderer()=0
return pointer to the renderer (no transfer of ownership)
QgsMarkerSymbol * centerSymbol()
Returns the symbol for the center of a displacement group (but not ownership of the symbol)...
double minimumLabelScale() const
Returns the minimum map scale (i.e.
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 QgsRendererWidget * createRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *oldRenderer)
Return new instance of settings widget for the renderer.
QgsSymbolWidgetContext context() const
Returns the context in which the renderer widget is shown, e.g., the associated map canvas and expres...
Base class for renderer settings widgets.
void setLabelFont(const QFont &font)
Sets the font used for labeling points.
void setTolerance(double distance)
Sets the tolerance distance for grouping points.
QgsVectorLayer * mLayer
void setLabelColor(const QColor &color)
Sets the color to use for for labeling points.
void setToleranceMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale object for the distance tolerance.
void setToleranceUnit(QgsUnitTypes::RenderUnit unit)
Sets the units for the tolerance distance.
void changed()
Emitted when the symbol&#39;s settings are changed.
double circleRadiusAddition() const
Returns the factor for increasing the ring size of displacement groups.
Container of fields for a vector layer.
Definition: qgsfields.h:42
QStringList renderersList(QgsRendererAbstractMetadata::LayerTypes layerTypes=QgsRendererAbstractMetadata::All) const
Returns a list of available renderers.
void scaleChanged(double scale)
Emitted when user has finished editing/selecting a new scale.
QString labelAttributeName() const
Returns the attribute name used for labeling points, or an empty string if no labeling will be done b...
void setCenterSymbol(QgsMarkerSymbol *symbol)
Sets the center symbol for a displacement group.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:173
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsUnitTypes::RenderUnit toleranceUnit() const
Returns the units for the tolerance distance.
QFont labelFont() const
Returns the font used for labeling points.
QString type() const
Definition: qgsrenderer.h:126
QgsFields fields() const override
Returns the list of fields of this layer.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
Compatible with point layers.
void setCircleColor(const QColor &color)
Sets the color used for drawing the displacement group circle.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsWkbTypes::Type wkbType() const override
Returns the WKBType or WKBUnknown in case of error.
points (e.g., for font sizes)
Definition: qgsunittypes.h:107
void setLabelAttributeName(const QString &name)
Sets the attribute name for labeling points.
QColor circleColor() const
Returns the color used for drawing the displacement group circle.
Place points in concentric rings around group.
QgsRendererAbstractMetadata * rendererMetadata(const QString &rendererName)
Returns the metadata for a specified renderer.
void changed()
Emitted when the widget&#39;s text format settings are changed.
void setPlacement(Placement placement)
Sets the placement method used for dispersing the points.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setAdditionalExpressionContextScopes(const QList< QgsExpressionContextScope > &scopes)
Sets a list of additional expression context scopes to show as available within the layer...
void widgetChanged()
Emitted when the widget state changes.
double tolerance() const
Returns the tolerance distance for grouping points.
const QgsMapUnitScale & toleranceMapUnitScale() const
Returns the map unit scale object for the distance tolerance.
Place points in a single ring around group.
A renderer that automatically displaces points with the same geographic location. ...
void colorChanged(const QColor &color)
Is emitted whenever a new color is set for the button.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
Marker symbol.
Definition: qgssymbol.h:85
const QgsFeatureRenderer * embeddedRenderer() const override
Returns the current embedded renderer (subrenderer) for this feature renderer.
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsSymbolWidgetContext mContext
Context in which widget is shown.
void setMinimumLabelScale(double scale)
Sets the minimum map scale (i.e.
Stores metadata about one renderer class.
static const QString EXPR_CLUSTER_SIZE
Inbuilt variable name for cluster size variable.
Configure font settings for use with QFont objects.
Definition: qgsfontbutton.h:57
QString name
Definition: qgsmaplayer.h:60
QgsFeatureRenderer * renderer() override
return pointer to the renderer (no transfer of ownership)
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
void setContext(const QgsSymbolWidgetContext &context) override
Sets the context in which the renderer widget is shown, e.g., the associated map canvas and expressio...
Placement placement() const
Returns the placement method used for dispersing the points.
void setCircleRadiusAddition(double distance)
Sets a factor for increasing the ring size of displacement groups.
void setEmbeddedRenderer(QgsFeatureRenderer *r) override
Sets an embedded renderer (subrenderer) for this feature renderer.
Represents a vector layer which manages a vector based data sets.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
static QgsPointDisplacementRenderer * convertFromRenderer(const QgsFeatureRenderer *renderer)
Creates a QgsPointDisplacementRenderer from an existing renderer.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
static QgsRendererRegistry * rendererRegistry()
Returns the application&#39;s renderer registry, used for managing vector layer renderers.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
virtual QgsMarkerSymbol * clone() const override
Get a deep copy of this symbol.
Definition: qgssymbol.cpp:1506
void setCircleWidth(double width)
Sets the line width for the displacement group circle.
QColor labelColor() const
Returns the color used for for labeling points.
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
double circleWidth() const
Returns the line width for the displacement group circle in mm.
QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)