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