QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 );
89  mLayerRenderingGroupBox->setSettingGroup( QStringLiteral( "layerRenderingGroupBox" ) );
90 
91  // can be embedded in vector layer properties
92  if ( embedded )
93  {
94  buttonBox->hide();
95  layout()->setContentsMargins( 0, 0, 0, 0 );
96  }
97 
98  // initialize registry's widget functions
99  _initRendererWidgetFunctions();
100 
102  QStringList renderers = reg->renderersList( mLayer );
103  Q_FOREACH ( const QString &name, renderers )
104  {
106  cboRenderers->addItem( m->icon(), m->visibleName(), name );
107  }
108 
109  cboRenderers->setCurrentIndex( -1 ); // set no current renderer
110 
111  connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsRendererPropertiesDialog::onOK );
112 
113  // connect layer opacity slider and spin box
114  connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::rendererChanged );
115  connect( checkboxEnableOrderBy, &QAbstractButton::toggled, btnOrderBy, &QWidget::setEnabled );
116  connect( btnOrderBy, &QAbstractButton::clicked, this, &QgsRendererPropertiesDialog::showOrderByDialog );
117 
118  syncToLayer();
119 
120  QList<QWidget *> widgets;
121  widgets << mOpacityWidget
122  << cboRenderers
123  << checkboxEnableOrderBy
124  << mBlendModeComboBox
125  << mFeatureBlendComboBox
126  << mEffectWidget;
127 
128  connectValueChanged( widgets, SIGNAL( widgetChanged() ) );
129  connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
130 }
131 
132 void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
133 {
134  Q_FOREACH ( QWidget *widget, widgets )
135  {
136  if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
137  {
138  connect( w, SIGNAL( changed ), this, slot );
139  }
140  else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
141  {
142  connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
143  }
144  else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
145  {
146  connect( w, SIGNAL( opacityChanged( double ) ), this, slot );
147  }
148  else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
149  {
150  connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
151  }
152  else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
153  {
154  connect( w, SIGNAL( valueChanged( int ) ), this, slot );
155  }
156  else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
157  {
158  connect( w, SIGNAL( valueChanged( double ) ), this, slot );
159  }
160  else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
161  {
162  connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
163  }
164  else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
165  {
166  connect( w, SIGNAL( toggled( bool ) ), this, slot );
167  }
168  else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
169  {
170  connect( w, SIGNAL( textEdited( QString ) ), this, slot );
171  connect( w, SIGNAL( textChanged( QString ) ), this, slot );
172  }
173  else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
174  {
175  connect( w, SIGNAL( changed() ), this, slot );
176  }
177  }
178 }
179 
181 {
182  delete mPaintEffect;
183 }
184 
186 {
187  mMapCanvas = canvas;
188  if ( mActiveWidget )
189  {
190  QgsSymbolWidgetContext context;
191  context.setMapCanvas( mMapCanvas );
192  mActiveWidget->setContext( context );
193  }
194 }
195 
197 {
198  mDockMode = dockMode;
199  mEffectWidget->setDockMode( dockMode );
200  if ( mActiveWidget )
201  mActiveWidget->setDockMode( mDockMode );
202 }
203 
204 
206 {
207  if ( cboRenderers->currentIndex() == -1 )
208  {
209  QgsDebugMsg( QStringLiteral( "No current item -- this should never happen!" ) );
210  return;
211  }
212 
213  QString rendererName = cboRenderers->currentData().toString();
214 
215  //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
216  QgsFeatureRenderer *oldRenderer = nullptr;
218  {
219  oldRenderer = mActiveWidget->renderer()->clone();
220  }
221  else
222  {
223  oldRenderer = mLayer->renderer()->clone();
224  }
225 
226  // get rid of old active widget (if any)
227  if ( mActiveWidget )
228  {
229  stackedWidget->removeWidget( mActiveWidget );
230 
231  delete mActiveWidget;
232  mActiveWidget = nullptr;
233  }
234 
235  QgsRendererWidget *w = nullptr;
237  if ( m )
238  w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
239  delete oldRenderer;
240 
241  if ( w )
242  {
243  // instantiate the widget and set as active
244  mActiveWidget = w;
245  stackedWidget->addWidget( mActiveWidget );
246  stackedWidget->setCurrentWidget( mActiveWidget );
247  if ( mActiveWidget->renderer() )
248  {
249  if ( mMapCanvas )
250  {
251  QgsSymbolWidgetContext context;
252  context.setMapCanvas( mMapCanvas );
253  mActiveWidget->setContext( context );
254  }
255  changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
257  }
260  w->setDockMode( mDockMode );
261  }
262  else
263  {
264  // set default "no edit widget available" page
265  stackedWidget->setCurrentWidget( pageNoWidget );
266  }
267 }
268 
270 {
271  if ( !mActiveWidget || !mLayer )
272  {
273  return;
274  }
275 
277 
279  if ( renderer )
280  {
281  renderer->setPaintEffect( mPaintEffect->clone() );
282  // set the order by
283  renderer->setOrderBy( mOrderBy );
284  renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
285 
286  mLayer->setRenderer( renderer->clone() );
287  }
288 
289  // set the blend modes for the layer
290  mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
291  mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
292 
293  // set opacity for the layer
294  mLayer->setOpacity( mOpacityWidget->opacity() );
295 }
296 
298 {
299  apply();
300  accept();
301 }
302 
304 {
305  QgsDebugMsg( QStringLiteral( "Open panel!!!" ) );
306  if ( mDockMode )
307  {
308  QgsDebugMsg( QStringLiteral( "DOCK MODE" ) );
309  emit showPanel( panel );
310  }
311  else
312  {
313  QgsDebugMsg( QStringLiteral( "DIALOG MODE" ) );
314  // Show the dialog version if no one is connected
315  QDialog *dlg = new QDialog();
316  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
317  QgsSettings settings;
318  dlg->restoreGeometry( settings.value( key ).toByteArray() );
319  dlg->setWindowTitle( panel->panelTitle() );
320  dlg->setLayout( new QVBoxLayout() );
321  dlg->layout()->addWidget( panel );
322  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
323  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
324  dlg->layout()->addWidget( buttonBox );
325  dlg->exec();
326  settings.setValue( key, dlg->saveGeometry() );
327  panel->acceptPanel();
328  }
329 }
330 
331 void QgsRendererPropertiesDialog::syncToLayer()
332 {
333  // Blend mode
334  mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
335 
336  // Feature blend mode
337  mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
338 
339  // Layer opacity
340  mOpacityWidget->setOpacity( mLayer->opacity() );
341 
342  //paint effect widget
343  if ( mLayer->renderer() )
344  {
345  if ( mLayer->renderer()->paintEffect() )
346  {
348  mEffectWidget->setPaintEffect( mPaintEffect );
349  }
350 
352  }
353 
354  // setup slot rendererChanged()
355  //setup order by
356  if ( mLayer->renderer() &&
358  {
359  checkboxEnableOrderBy->setChecked( true );
360  }
361  else
362  {
363  btnOrderBy->setEnabled( false );
364  checkboxEnableOrderBy->setChecked( false );
365  }
366 
367  if ( mLayer->renderer() )
368  {
369  // set current renderer from layer
370  QString rendererName = mLayer->renderer()->type();
371 
372  int rendererIdx = cboRenderers->findData( rendererName );
373  cboRenderers->setCurrentIndex( rendererIdx );
374 
375  // no renderer found... this mustn't happen
376  Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
377  }
378 
379 }
380 
381 void QgsRendererPropertiesDialog::showOrderByDialog()
382 {
383  QgsOrderByDialog dlg( mLayer, this );
384 
385  dlg.setOrderBy( mOrderBy );
386  if ( dlg.exec() )
387  {
388  mOrderBy = dlg.orderBy();
389  emit widgetChanged();
390  }
391 }
392 
393 void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
394 {
395  mOrderBy = orderBy;
396  checkboxEnableOrderBy->setChecked( orderByEnabled );
397 }
398 
399 void QgsRendererPropertiesDialog::updateUIState( bool hidden )
400 {
401  mLayerRenderingGroupBox->setHidden( hidden );
402  cboRenderers->setHidden( hidden );
403 }
404 
405 
407 {
408  // Ignore the ESC key to avoid close the dialog without the properties window
409  if ( !isWindow() && e->key() == Qt::Key_Escape )
410  {
411  e->ignore();
412  }
413  else
414  {
415  QDialog::keyPressEvent( e );
416  }
417 }
QStringList renderersList(QgsRendererAbstractMetadata::LayerTypes layerTypes=QgsRendererAbstractMetadata::All) const
Returns a list of available renderers.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
The QgsFieldExpressionWidget class reates a widget to choose fields and edit expressions It contains ...
QString type() const
Definition: qgsrenderer.h:129
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.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
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.
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 setFeatureBlendMode(QPainter::CompositionMode blendMode)
Sets the blending mode used for rendering each feature.
A cross platform button subclass for selecting colors.
Registry of renderers.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
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.
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: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.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
A button for controlling property overrides which may apply to a widget.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the renderer.
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.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
void widgetChanged()
Emitted when the widget state changes.
bool orderByEnabled() const
Returns whether custom ordering will be applied before features are processed by this renderer...
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 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.
QgsFeatureRequest::OrderBy orderBy() const
Gets the order in which features shall be processed by this renderer.
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...
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.