QGIS API Documentation  3.2.0-Bonn (bc43194)
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  QString iconPath = QgsApplication::defaultThemePath() + iconName;
57  QPixmap pix;
58  if ( pix.load( iconPath ) )
59  m->setIcon( pix );
60  }
61 
62  QgsDebugMsg( "Set for " + name );
63  return true;
64 }
65 
66 static void _initRendererWidgetFunctions()
67 {
68  static bool sInitialized = false;
69  if ( sInitialized )
70  return;
71 
72  _initRenderer( QStringLiteral( "singleSymbol" ), QgsSingleSymbolRendererWidget::create, QStringLiteral( "rendererSingleSymbol.svg" ) );
73  _initRenderer( QStringLiteral( "categorizedSymbol" ), QgsCategorizedSymbolRendererWidget::create, QStringLiteral( "rendererCategorizedSymbol.svg" ) );
74  _initRenderer( QStringLiteral( "graduatedSymbol" ), QgsGraduatedSymbolRendererWidget::create, QStringLiteral( "rendererGraduatedSymbol.svg" ) );
75  _initRenderer( QStringLiteral( "RuleRenderer" ), QgsRuleBasedRendererWidget::create, QStringLiteral( "rendererRuleBasedSymbol.svg" ) );
76  _initRenderer( QStringLiteral( "pointDisplacement" ), QgsPointDisplacementRendererWidget::create, QStringLiteral( "rendererPointDisplacementSymbol.svg" ) );
77  _initRenderer( QStringLiteral( "pointCluster" ), QgsPointClusterRendererWidget::create, QStringLiteral( "rendererPointClusterSymbol.svg" ) );
78  _initRenderer( QStringLiteral( "invertedPolygonRenderer" ), QgsInvertedPolygonRendererWidget::create, QStringLiteral( "rendererInvertedSymbol.svg" ) );
79  _initRenderer( QStringLiteral( "heatmapRenderer" ), QgsHeatmapRendererWidget::create, QStringLiteral( "rendererHeatmapSymbol.svg" ) );
80  _initRenderer( QStringLiteral( "25dRenderer" ), Qgs25DRendererWidget::create, QStringLiteral( "renderer25dSymbol.svg" ) );
81  _initRenderer( QStringLiteral( "nullSymbol" ), QgsNullSymbolRendererWidget::create, QStringLiteral( "rendererNullSymbol.svg" ) );
82  sInitialized = true;
83 }
84 
85 QgsRendererPropertiesDialog::QgsRendererPropertiesDialog( QgsVectorLayer *layer, QgsStyle *style, bool embedded, QWidget *parent )
86  : QDialog( parent )
87  , mLayer( layer )
88  , mStyle( style )
89 
90 {
91  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  Q_FOREACH ( const QString &name, renderers )
107  {
109  cboRenderers->addItem( m->icon(), m->visibleName(), name );
110  }
111 
112  cboRenderers->setCurrentIndex( -1 ); // set no current renderer
113 
114  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsRendererPropertiesDialog::onOK );
115 
116  // connect layer opacity slider and spin box
117  connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::rendererChanged );
118  connect( checkboxEnableOrderBy, &QAbstractButton::toggled, btnOrderBy, &QWidget::setEnabled );
119  connect( btnOrderBy, &QAbstractButton::clicked, this, &QgsRendererPropertiesDialog::showOrderByDialog );
120 
121  syncToLayer();
122 
123  QList<QWidget *> widgets;
124  widgets << mOpacityWidget
125  << cboRenderers
126  << checkboxEnableOrderBy
127  << mBlendModeComboBox
128  << mFeatureBlendComboBox
129  << mEffectWidget;
130 
131  connectValueChanged( widgets, SIGNAL( widgetChanged() ) );
132  connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
133 }
134 
135 void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
136 {
137  Q_FOREACH ( QWidget *widget, widgets )
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  mDockMode = dockMode;
202  mEffectWidget->setDockMode( dockMode );
203  if ( mActiveWidget )
204  mActiveWidget->setDockMode( mDockMode );
205 }
206 
207 
209 {
210  if ( cboRenderers->currentIndex() == -1 )
211  {
212  QgsDebugMsg( "No current item -- this should never happen!" );
213  return;
214  }
215 
216  QString rendererName = cboRenderers->currentData().toString();
217 
218  //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
219  QgsFeatureRenderer *oldRenderer = nullptr;
221  {
222  oldRenderer = mActiveWidget->renderer()->clone();
223  }
224  else
225  {
226  oldRenderer = mLayer->renderer()->clone();
227  }
228 
229  // get rid of old active widget (if any)
230  if ( mActiveWidget )
231  {
232  stackedWidget->removeWidget( mActiveWidget );
233 
234  delete mActiveWidget;
235  mActiveWidget = nullptr;
236  }
237 
238  QgsRendererWidget *w = nullptr;
240  if ( m )
241  w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
242  delete oldRenderer;
243 
244  if ( w )
245  {
246  // instantiate the widget and set as active
247  mActiveWidget = w;
248  stackedWidget->addWidget( mActiveWidget );
249  stackedWidget->setCurrentWidget( mActiveWidget );
250  if ( mActiveWidget->renderer() )
251  {
252  if ( mMapCanvas )
253  {
254  QgsSymbolWidgetContext context;
255  context.setMapCanvas( mMapCanvas );
256  mActiveWidget->setContext( context );
257  }
258  changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
260  }
263  w->setDockMode( mDockMode );
264  }
265  else
266  {
267  // set default "no edit widget available" page
268  stackedWidget->setCurrentWidget( pageNoWidget );
269  }
270 }
271 
273 {
274  if ( !mActiveWidget || !mLayer )
275  {
276  return;
277  }
278 
280 
282  if ( renderer )
283  {
284  renderer->setPaintEffect( mPaintEffect->clone() );
285  // set the order by
286  renderer->setOrderBy( mOrderBy );
287  renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
288 
289  mLayer->setRenderer( renderer->clone() );
290  }
291 
292  // set the blend modes for the layer
293  mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
294  mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
295 
296  // set opacity for the layer
297  mLayer->setOpacity( mOpacityWidget->opacity() );
298 }
299 
301 {
302  apply();
303  accept();
304 }
305 
307 {
308  QgsDebugMsg( "Open panel!!!" );
309  if ( mDockMode )
310  {
311  QgsDebugMsg( "DOCK MODE" );
312  emit showPanel( panel );
313  }
314  else
315  {
316  QgsDebugMsg( "DIALOG MODE" );
317  // Show the dialog version if no one is connected
318  QDialog *dlg = new QDialog();
319  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
320  QgsSettings settings;
321  dlg->restoreGeometry( settings.value( key ).toByteArray() );
322  dlg->setWindowTitle( panel->panelTitle() );
323  dlg->setLayout( new QVBoxLayout() );
324  dlg->layout()->addWidget( panel );
325  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
326  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
327  dlg->layout()->addWidget( buttonBox );
328  dlg->exec();
329  settings.setValue( key, dlg->saveGeometry() );
330  panel->acceptPanel();
331  }
332 }
333 
334 void QgsRendererPropertiesDialog::syncToLayer()
335 {
336  // Blend mode
337  mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
338 
339  // Feature blend mode
340  mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
341 
342  // Layer opacity
343  mOpacityWidget->setOpacity( mLayer->opacity() );
344 
345  //paint effect widget
346  if ( mLayer->renderer() )
347  {
348  if ( mLayer->renderer()->paintEffect() )
349  {
351  mEffectWidget->setPaintEffect( mPaintEffect );
352  }
353 
355  }
356 
357  // setup slot rendererChanged()
358  //setup order by
359  if ( mLayer->renderer() &&
361  {
362  checkboxEnableOrderBy->setChecked( true );
363  }
364  else
365  {
366  btnOrderBy->setEnabled( false );
367  checkboxEnableOrderBy->setChecked( false );
368  }
369 
370  if ( mLayer->renderer() )
371  {
372  // set current renderer from layer
373  QString rendererName = mLayer->renderer()->type();
374 
375  int rendererIdx = cboRenderers->findData( rendererName );
376  cboRenderers->setCurrentIndex( rendererIdx );
377 
378  // no renderer found... this mustn't happen
379  Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
380  }
381 
382 }
383 
384 void QgsRendererPropertiesDialog::showOrderByDialog()
385 {
386  QgsOrderByDialog dlg( mLayer, this );
387 
388  dlg.setOrderBy( mOrderBy );
389  if ( dlg.exec() )
390  {
391  mOrderBy = dlg.orderBy();
392  emit widgetChanged();
393  }
394 }
395 
396 void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
397 {
398  mOrderBy = orderBy;
399  checkboxEnableOrderBy->setChecked( orderByEnabled );
400 }
401 
402 void QgsRendererPropertiesDialog::updateUIState( bool hidden )
403 {
404  mLayerRenderingGroupBox->setHidden( hidden );
405  cboRenderers->setHidden( hidden );
406 }
407 
408 
410 {
411  // Ignore the ESC key to avoid close the dialog without the properties window
412  if ( !isWindow() && e->key() == Qt::Key_Escape )
413  {
414  e->ignore();
415  }
416  else
417  {
418  QDialog::keyPressEvent( e );
419  }
420 }
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)
Set 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.
static QString defaultThemePath()
Returns the path to the default theme directory.
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.
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.
QString iconPath(const QString &iconFile)
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:74
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 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 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
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.
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.