QGIS API Documentation  3.6.0-Noosa (5873452)
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  mMapCanvas = context.mapCanvas();
199  mMessageBar = context.messageBar();
200  if ( mActiveWidget )
201  {
202  mActiveWidget->setContext( context );
203  }
204 }
205 
207 {
208  mDockMode = dockMode;
209  mEffectWidget->setDockMode( dockMode );
210  if ( mActiveWidget )
211  mActiveWidget->setDockMode( mDockMode );
212 }
213 
214 
216 {
217  if ( cboRenderers->currentIndex() == -1 )
218  {
219  QgsDebugMsg( QStringLiteral( "No current item -- this should never happen!" ) );
220  return;
221  }
222 
223  QString rendererName = cboRenderers->currentData().toString();
224 
225  //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
226  QgsFeatureRenderer *oldRenderer = nullptr;
228  {
229  oldRenderer = mActiveWidget->renderer()->clone();
230  }
231  else
232  {
233  oldRenderer = mLayer->renderer()->clone();
234  }
235 
236  // get rid of old active widget (if any)
237  if ( mActiveWidget )
238  {
239  stackedWidget->removeWidget( mActiveWidget );
240 
241  delete mActiveWidget;
242  mActiveWidget = nullptr;
243  }
244 
245  QgsRendererWidget *w = nullptr;
247  if ( m )
248  w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
249  delete oldRenderer;
250 
251  if ( w )
252  {
253  // instantiate the widget and set as active
254  mActiveWidget = w;
255  stackedWidget->addWidget( mActiveWidget );
256  stackedWidget->setCurrentWidget( mActiveWidget );
257  if ( mActiveWidget->renderer() )
258  {
259  if ( mMapCanvas || mMessageBar )
260  {
261  QgsSymbolWidgetContext context;
262  context.setMapCanvas( mMapCanvas );
263  context.setMessageBar( mMessageBar );
264  mActiveWidget->setContext( context );
265  }
266  changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
268  }
271  w->setDockMode( mDockMode );
272  }
273  else
274  {
275  // set default "no edit widget available" page
276  stackedWidget->setCurrentWidget( pageNoWidget );
277  }
278 }
279 
281 {
282  if ( !mActiveWidget || !mLayer )
283  {
284  return;
285  }
286 
288 
290  if ( renderer )
291  {
292  renderer->setPaintEffect( mPaintEffect->clone() );
293  // set the order by
294  renderer->setOrderBy( mOrderBy );
295  renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
296 
297  mLayer->setRenderer( renderer->clone() );
298  }
299 
300  // set the blend modes for the layer
301  mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
302  mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
303 
304  // set opacity for the layer
305  mLayer->setOpacity( mOpacityWidget->opacity() );
306 }
307 
309 {
310  apply();
311  accept();
312 }
313 
315 {
316  QgsDebugMsg( QStringLiteral( "Open panel!!!" ) );
317  if ( mDockMode )
318  {
319  QgsDebugMsg( QStringLiteral( "DOCK MODE" ) );
320  emit showPanel( panel );
321  }
322  else
323  {
324  QgsDebugMsg( QStringLiteral( "DIALOG MODE" ) );
325  // Show the dialog version if no one is connected
326  QDialog *dlg = new QDialog();
327  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
328  QgsSettings settings;
329  dlg->restoreGeometry( settings.value( key ).toByteArray() );
330  dlg->setWindowTitle( panel->panelTitle() );
331  dlg->setLayout( new QVBoxLayout() );
332  dlg->layout()->addWidget( panel );
333  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
334  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
335  dlg->layout()->addWidget( buttonBox );
336  dlg->exec();
337  settings.setValue( key, dlg->saveGeometry() );
338  panel->acceptPanel();
339  }
340 }
341 
342 void QgsRendererPropertiesDialog::syncToLayer()
343 {
344  // Blend mode
345  mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
346 
347  // Feature blend mode
348  mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
349 
350  // Layer opacity
351  mOpacityWidget->setOpacity( mLayer->opacity() );
352 
353  //paint effect widget
354  if ( mLayer->renderer() )
355  {
356  if ( mLayer->renderer()->paintEffect() )
357  {
359  mEffectWidget->setPaintEffect( mPaintEffect );
360  }
361 
363  }
364 
365  // setup slot rendererChanged()
366  //setup order by
367  if ( mLayer->renderer() &&
369  {
370  checkboxEnableOrderBy->setChecked( true );
371  }
372  else
373  {
374  btnOrderBy->setEnabled( false );
375  checkboxEnableOrderBy->setChecked( false );
376  }
377 
378  if ( mLayer->renderer() )
379  {
380  // set current renderer from layer
381  QString rendererName = mLayer->renderer()->type();
382 
383  int rendererIdx = cboRenderers->findData( rendererName );
384  cboRenderers->setCurrentIndex( rendererIdx );
385 
386  // no renderer found... this mustn't happen
387  Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
388  }
389 
390 }
391 
392 void QgsRendererPropertiesDialog::showOrderByDialog()
393 {
394  QgsOrderByDialog dlg( mLayer, this );
395 
396  dlg.setOrderBy( mOrderBy );
397  if ( dlg.exec() )
398  {
399  mOrderBy = dlg.orderBy();
400  emit widgetChanged();
401  }
402 }
403 
404 void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
405 {
406  mOrderBy = orderBy;
407  checkboxEnableOrderBy->setChecked( orderByEnabled );
408 }
409 
410 void QgsRendererPropertiesDialog::updateUIState( bool hidden )
411 {
412  mLayerRenderingGroupBox->setHidden( hidden );
413  cboRenderers->setHidden( hidden );
414 }
415 
416 
418 {
419  // Ignore the ESC key to avoid close the dialog without the properties window
420  if ( !isWindow() && e->key() == Qt::Key_Escape )
421  {
422  e->ignore();
423  }
424  else
425  {
426  QDialog::keyPressEvent( e );
427  }
428 }
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.
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.
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.