QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsrendererpropertiesdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrendererpropertiesdialog.cpp
3  ---------------------
4  begin : December 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
16 
17 #include "qgsrenderer.h"
18 #include "qgsrendererregistry.h"
19 
20 #include "qgsrendererwidget.h"
30 #include "qgs25drendererwidget.h"
32 #include "qgspanelwidget.h"
33 #include "qgspainteffect.h"
34 
35 #include "qgsorderbydialog.h"
36 #include "qgsapplication.h"
37 #include "qgslogger.h"
38 #include "qgsvectorlayer.h"
39 
40 #include <QKeyEvent>
41 #include <QMessageBox>
42 
43 static bool _initRenderer( const QString &name, QgsRendererWidgetFunc f, const QString &iconName = QString() )
44 {
47  if ( !am )
48  return false;
49  QgsRendererMetadata *m = dynamic_cast<QgsRendererMetadata *>( am );
50  if ( !m )
51  return false;
52 
53  m->setWidgetFunction( f );
54 
55  if ( !iconName.isEmpty() )
56  {
57  m->setIcon( QgsApplication::getThemeIcon( iconName ) );
58  }
59 
60  QgsDebugMsgLevel( "Set for " + name, 2 );
61  return true;
62 }
63 
64 static void _initRendererWidgetFunctions()
65 {
66  static bool sInitialized = false;
67  if ( sInitialized )
68  return;
69 
70  _initRenderer( QStringLiteral( "singleSymbol" ), QgsSingleSymbolRendererWidget::create, QStringLiteral( "rendererSingleSymbol.svg" ) );
71  _initRenderer( QStringLiteral( "categorizedSymbol" ), QgsCategorizedSymbolRendererWidget::create, QStringLiteral( "rendererCategorizedSymbol.svg" ) );
72  _initRenderer( QStringLiteral( "graduatedSymbol" ), QgsGraduatedSymbolRendererWidget::create, QStringLiteral( "rendererGraduatedSymbol.svg" ) );
73  _initRenderer( QStringLiteral( "RuleRenderer" ), QgsRuleBasedRendererWidget::create, QStringLiteral( "rendererRuleBasedSymbol.svg" ) );
74  _initRenderer( QStringLiteral( "pointDisplacement" ), QgsPointDisplacementRendererWidget::create, QStringLiteral( "rendererPointDisplacementSymbol.svg" ) );
75  _initRenderer( QStringLiteral( "pointCluster" ), QgsPointClusterRendererWidget::create, QStringLiteral( "rendererPointClusterSymbol.svg" ) );
76  _initRenderer( QStringLiteral( "invertedPolygonRenderer" ), QgsInvertedPolygonRendererWidget::create, QStringLiteral( "rendererInvertedSymbol.svg" ) );
77  _initRenderer( QStringLiteral( "mergedFeatureRenderer" ), QgsMergedFeatureRendererWidget::create, QStringLiteral( "rendererMergedFeatures.svg" ) );
78  _initRenderer( QStringLiteral( "heatmapRenderer" ), QgsHeatmapRendererWidget::create, QStringLiteral( "rendererHeatmapSymbol.svg" ) );
79  _initRenderer( QStringLiteral( "25dRenderer" ), Qgs25DRendererWidget::create, QStringLiteral( "renderer25dSymbol.svg" ) );
80  _initRenderer( QStringLiteral( "nullSymbol" ), QgsNullSymbolRendererWidget::create, QStringLiteral( "rendererNullSymbol.svg" ) );
81  sInitialized = true;
82 }
83 
84 QgsRendererPropertiesDialog::QgsRendererPropertiesDialog( QgsVectorLayer *layer, QgsStyle *style, bool embedded, QWidget *parent )
85  : QDialog( parent )
86  , mLayer( layer )
87  , mStyle( style )
88 
89 {
90  setupUi( this );
92  mLayerRenderingGroupBox->setSettingGroup( QStringLiteral( "layerRenderingGroupBox" ) );
93 
94  // can be embedded in vector layer properties
95  if ( embedded )
96  {
97  buttonBox->hide();
98  layout()->setContentsMargins( 0, 0, 0, 0 );
99  }
100 
101  // initialize registry's widget functions
102  _initRendererWidgetFunctions();
103 
105  QStringList renderers = reg->renderersList( mLayer );
106  const auto constRenderers = renderers;
107  for ( const QString &name : constRenderers )
108  {
110  cboRenderers->addItem( m->icon(), m->visibleName(), name );
111  }
112 
113  cboRenderers->setCurrentIndex( -1 ); // set no current renderer
114 
115  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsRendererPropertiesDialog::onOK );
116 
117  // connect layer opacity slider and spin box
118  connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::rendererChanged );
119  connect( checkboxEnableOrderBy, &QAbstractButton::toggled, btnOrderBy, &QWidget::setEnabled );
120  connect( btnOrderBy, &QAbstractButton::clicked, this, &QgsRendererPropertiesDialog::showOrderByDialog );
121 
122  syncToLayer();
123 
124  QList<QWidget *> widgets;
125  widgets << mOpacityWidget
126  << cboRenderers
127  << checkboxEnableOrderBy
128  << mBlendModeComboBox
129  << mFeatureBlendComboBox
130  << mEffectWidget;
131 
132  connectValueChanged( widgets, SIGNAL( widgetChanged() ) );
133  connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
134 }
135 
136 void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
137 {
138  for ( QWidget *widget : widgets )
139  {
140  if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
141  {
142  connect( w, SIGNAL( changed ), this, slot );
143  }
144  else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
145  {
146  connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
147  }
148  else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
149  {
150  connect( w, SIGNAL( opacityChanged( double ) ), this, slot );
151  }
152  else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
153  {
154  connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
155  }
156  else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
157  {
158  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
159  }
160  else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
161  {
162  connect( w, SIGNAL( valueChanged( double ) ), this, slot );
163  }
164  else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
165  {
166  connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
167  }
168  else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
169  {
170  connect( w, SIGNAL( toggled( bool ) ), this, slot );
171  }
172  else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
173  {
174  connect( w, SIGNAL( textEdited( QString ) ), this, slot );
175  connect( w, SIGNAL( textChanged( QString ) ), this, slot );
176  }
177  else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
178  {
179  connect( w, SIGNAL( changed() ), this, slot );
180  }
181  }
182 }
183 
185 {
186  delete mPaintEffect;
187 }
188 
190 {
191  mMapCanvas = canvas;
192  if ( mActiveWidget )
193  {
194  QgsSymbolWidgetContext context;
195  context.setMapCanvas( mMapCanvas );
196  mActiveWidget->setContext( context );
197  }
198 }
199 
201 {
202  mMapCanvas = context.mapCanvas();
203  mMessageBar = context.messageBar();
204  if ( mActiveWidget )
205  {
206  mActiveWidget->setContext( context );
207  }
208 }
209 
211 {
212  mDockMode = dockMode;
213  mEffectWidget->setDockMode( dockMode );
214  if ( mActiveWidget )
215  mActiveWidget->setDockMode( mDockMode );
216 }
217 
218 
220 {
221  if ( cboRenderers->currentIndex() == -1 )
222  {
223  QgsDebugMsg( QStringLiteral( "No current item -- this should never happen!" ) );
224  return;
225  }
226 
227  QString rendererName = cboRenderers->currentData().toString();
228 
229  //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
230  QgsFeatureRenderer *oldRenderer = nullptr;
232  {
233  oldRenderer = mActiveWidget->renderer()->clone();
234  }
235  else
236  {
237  oldRenderer = mLayer->renderer()->clone();
238  }
239 
240  // get rid of old active widget (if any)
241  if ( mActiveWidget )
242  {
243  stackedWidget->removeWidget( mActiveWidget );
244 
245  delete mActiveWidget;
246  mActiveWidget = nullptr;
247  }
248 
249  QgsRendererWidget *w = nullptr;
251  if ( m )
252  w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
253  delete oldRenderer;
254 
255  if ( w )
256  {
257  // instantiate the widget and set as active
258  mActiveWidget = w;
259  stackedWidget->addWidget( mActiveWidget );
260  stackedWidget->setCurrentWidget( mActiveWidget );
261  if ( mActiveWidget->renderer() )
262  {
263  if ( mMapCanvas || mMessageBar )
264  {
265  QgsSymbolWidgetContext context;
266  context.setMapCanvas( mMapCanvas );
267  context.setMessageBar( mMessageBar );
268  mActiveWidget->setContext( context );
269  }
270  changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
272  }
275  w->setDockMode( mDockMode );
276  }
277  else
278  {
279  // set default "no edit widget available" page
280  stackedWidget->setCurrentWidget( pageNoWidget );
281  }
282 }
283 
285 {
286  if ( !mActiveWidget || !mLayer )
287  {
288  return;
289  }
290 
292 
294  if ( renderer )
295  {
296  renderer->setPaintEffect( mPaintEffect->clone() );
297  // set the order by
298  renderer->setOrderBy( mOrderBy );
299  renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
300 
301  mLayer->setRenderer( renderer->clone() );
302  }
303 
304  // set the blend modes for the layer
305  mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
306  mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
307 
308  // set opacity for the layer
309  mLayer->setOpacity( mOpacityWidget->opacity() );
310 }
311 
313 {
314  apply();
315  accept();
316 }
317 
319 {
320  if ( mDockMode )
321  {
322  emit showPanel( panel );
323  }
324  else
325  {
326  // Show the dialog version if no one is connected
327  QDialog *dlg = new QDialog();
328  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
329  QgsSettings settings;
330  dlg->restoreGeometry( settings.value( key ).toByteArray() );
331  dlg->setWindowTitle( panel->panelTitle() );
332  dlg->setLayout( new QVBoxLayout() );
333  dlg->layout()->addWidget( panel );
334  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
335  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
336  dlg->layout()->addWidget( buttonBox );
337  dlg->exec();
338  settings.setValue( key, dlg->saveGeometry() );
339  panel->acceptPanel();
340  }
341 }
342 
343 void QgsRendererPropertiesDialog::syncToLayer()
344 {
345  // Blend mode
346  mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
347 
348  // Feature blend mode
349  mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
350 
351  // Layer opacity
352  mOpacityWidget->setOpacity( mLayer->opacity() );
353 
354  //paint effect widget
355  if ( mLayer->renderer() )
356  {
357  if ( mLayer->renderer()->paintEffect() )
358  {
360  mEffectWidget->setPaintEffect( mPaintEffect );
361  }
362 
364  }
365 
366  // setup slot rendererChanged()
367  //setup order by
368  if ( mLayer->renderer() &&
370  {
371  checkboxEnableOrderBy->setChecked( true );
372  }
373  else
374  {
375  btnOrderBy->setEnabled( false );
376  checkboxEnableOrderBy->setChecked( false );
377  }
378 
379  if ( mLayer->renderer() )
380  {
381  // set current renderer from layer
382  QString rendererName = mLayer->renderer()->type();
383 
384  int rendererIdx = cboRenderers->findData( rendererName );
385  cboRenderers->setCurrentIndex( rendererIdx );
386 
387  // no renderer found... this mustn't happen
388  Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
389  }
390 
391 }
392 
393 void QgsRendererPropertiesDialog::showOrderByDialog()
394 {
395  QgsOrderByDialog dlg( mLayer, this );
396 
397  dlg.setOrderBy( mOrderBy );
398  if ( dlg.exec() )
399  {
400  mOrderBy = dlg.orderBy();
401  emit widgetChanged();
402  }
403 }
404 
405 void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
406 {
407  mOrderBy = orderBy;
408  checkboxEnableOrderBy->setChecked( orderByEnabled );
409 }
410 
411 void QgsRendererPropertiesDialog::updateUIState( bool hidden )
412 {
413  mLayerRenderingGroupBox->setHidden( hidden );
414  cboRenderers->setHidden( hidden );
415 }
416 
417 
419 {
420  // Ignore the ESC key to avoid close the dialog without the properties window
421  if ( !isWindow() && e->key() == Qt::Key_Escape )
422  {
423  e->ignore();
424  }
425  else
426  {
427  QDialog::keyPressEvent( e );
428  }
429 }
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
static QgsRendererRegistry * rendererRegistry()
Returns the application's renderer registry, used for managing vector layer renderers.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
A cross platform button subclass for selecting colors.
A small widget consisting of a checkbox for enabling/disabling an effect stack and a button for openi...
void setOrderBy(const QgsFeatureRequest::OrderBy &orderBy)
Define the order in which features shall be processed by this renderer.
virtual QgsFeatureRenderer * clone() const =0
Create a deep copy of this renderer.
void setOrderByEnabled(bool enabled)
Sets whether custom ordering should be applied before features are processed by this renderer.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the renderer.
void setPaintEffect(QgsPaintEffect *effect)
Sets the current paint effect for the renderer.
QString type() const
Definition: qgsrenderer.h:141
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer.
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
Represents a list of OrderByClauses, with the most important first and the least important last.
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition: qgsgui.cpp:156
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:86
void setBlendMode(QPainter::CompositionMode blendMode)
Set the blending mode used for rendering a layer.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
virtual void setOpacity(double opacity)
Sets the opacity for the layer, where opacity is a value between 0 (totally transparent) and 1....
double opacity
Definition: qgsmaplayer.h:94
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Creates a new QgsNullSymbolRendererWidget object.
A widget for setting an opacity value.
This is a dialog to build and manage a list of order by clauses.
virtual QgsPaintEffect * clone() const =0
Duplicates an effect by creating a deep copy of the effect.
Base class for any widget that can be shown as a inline panel.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
QString panelTitle()
The title of the panel.
void widgetChanged()
Emitted when the widget state changes.
void acceptPanel()
Accept the panel.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Returns a new QgsPointClusterRendererWidget.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
A button for controlling property overrides which may apply to a widget.
Stores metadata about one renderer class.
QIcon icon() const
Returns an icon representing the renderer.
void setIcon(const QIcon &icon)
Sets 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.
Convenience metadata class that uses static functions to create renderer and its widget.
void setWidgetFunction(QgsRendererWidgetFunc f)
void connectValueChanged(const QList< QWidget * > &widgets, const char *slot)
Connect the given slot to the value changed event for the set of widgets Each widget is checked for t...
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
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 setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the dialog is shown, e.g., the associated map canvas and expression context...
QgsFeatureRequest::OrderBy mOrderBy
void apply()
Apply the changes from the dialog to the layer.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the dialog.
void layerVariablesChanged()
Emitted when expression context variables on the associated vector layers have been changed.
void widgetChanged()
Emitted when something on the widget has changed.
void onOK()
Apply and accept the changes for the dialog.
void keyPressEvent(QKeyEvent *event) override
void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
QgsRendererPropertiesDialog(QgsVectorLayer *layer, QgsStyle *style, bool embedded=false, QWidget *parent=nullptr)
Constructor for QgsRendererPropertiesDialog.
void rendererChanged()
called when user changes renderer type
Registry of renderers.
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.
void layerVariablesChanged()
Emitted when expression context variables on the associated vector layers have been changed.
virtual QgsFeatureRenderer * renderer()=0
Returns pointer to the renderer (no transfer of ownership)
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the renderer widget is shown, e.g., the associated map canvas and expressio...
void applyChanges()
This method should be called whenever the renderer is actually set on the layer.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
Represents a vector layer which manages a vector based data sets.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
void setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
void setRenderer(QgsFeatureRenderer *r)
Sets the feature renderer which will be invoked to represent this layer in 2D map views.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsRendererWidget *(* QgsRendererWidgetFunc)(QgsVectorLayer *, QgsStyle *, QgsFeatureRenderer *)