QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
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"
33#include "qgspanelwidget.h"
34#include "qgspainteffect.h"
35#include "qgsproject.h"
36#include "qgsprojectutils.h"
37
38#include "qgsorderbydialog.h"
39#include "qgsapplication.h"
40#include "qgslogger.h"
41#include "qgsvectorlayer.h"
42
43#include <QKeyEvent>
44#include <QMessageBox>
45
46static bool initVectorLayerRenderer( const QString &name, QgsRendererWidgetFunc f, const QString &iconName = QString() )
47{
50 if ( !am )
51 return false;
52 QgsRendererMetadata *m = dynamic_cast<QgsRendererMetadata *>( am );
53 if ( !m )
54 return false;
55
56 m->setWidgetFunction( f );
57
58 if ( !iconName.isEmpty() )
59 {
60 m->setIcon( QgsApplication::getThemeIcon( iconName ) );
61 }
62
63 QgsDebugMsgLevel( "Set for " + name, 2 );
64 return true;
65}
66
67void QgsRendererPropertiesDialog::initRendererWidgetFunctions()
68{
69 static bool sInitialized = false;
70 if ( sInitialized )
71 return;
72
73 initVectorLayerRenderer( QStringLiteral( "singleSymbol" ), QgsSingleSymbolRendererWidget::create, QStringLiteral( "rendererSingleSymbol.svg" ) );
74 initVectorLayerRenderer( QStringLiteral( "categorizedSymbol" ), QgsCategorizedSymbolRendererWidget::create, QStringLiteral( "rendererCategorizedSymbol.svg" ) );
75 initVectorLayerRenderer( QStringLiteral( "graduatedSymbol" ), QgsGraduatedSymbolRendererWidget::create, QStringLiteral( "rendererGraduatedSymbol.svg" ) );
76 initVectorLayerRenderer( QStringLiteral( "RuleRenderer" ), QgsRuleBasedRendererWidget::create, QStringLiteral( "rendererRuleBasedSymbol.svg" ) );
77 initVectorLayerRenderer( QStringLiteral( "pointDisplacement" ), QgsPointDisplacementRendererWidget::create, QStringLiteral( "rendererPointDisplacementSymbol.svg" ) );
78 initVectorLayerRenderer( QStringLiteral( "pointCluster" ), QgsPointClusterRendererWidget::create, QStringLiteral( "rendererPointClusterSymbol.svg" ) );
79 initVectorLayerRenderer( QStringLiteral( "invertedPolygonRenderer" ), QgsInvertedPolygonRendererWidget::create, QStringLiteral( "rendererInvertedSymbol.svg" ) );
80 initVectorLayerRenderer( QStringLiteral( "mergedFeatureRenderer" ), QgsMergedFeatureRendererWidget::create, QStringLiteral( "rendererMergedFeatures.svg" ) );
81 initVectorLayerRenderer( QStringLiteral( "heatmapRenderer" ), QgsHeatmapRendererWidget::create, QStringLiteral( "rendererHeatmapSymbol.svg" ) );
82 initVectorLayerRenderer( QStringLiteral( "25dRenderer" ), Qgs25DRendererWidget::create, QStringLiteral( "renderer25dSymbol.svg" ) );
83 initVectorLayerRenderer( QStringLiteral( "nullSymbol" ), QgsNullSymbolRendererWidget::create, QStringLiteral( "rendererNullSymbol.svg" ) );
84 initVectorLayerRenderer( QStringLiteral( "embeddedSymbol" ), QgsEmbeddedSymbolRendererWidget::create );
85 sInitialized = true;
86}
87
89 : QDialog( parent )
90 , mLayer( layer )
91 , mStyle( style )
92
93{
94 setupUi( this );
96 mLayerRenderingGroupBox->setSettingGroup( QStringLiteral( "layerRenderingGroupBox" ) );
97
98 // can be embedded in vector layer properties
99 if ( embedded )
100 {
101 buttonBox->hide();
102 layout()->setContentsMargins( 0, 0, 0, 0 );
103 }
104
105 // initialize registry's widget functions
106 initRendererWidgetFunctions();
107
109 const QStringList renderers = reg->renderersList( mLayer );
110 const auto constRenderers = renderers;
111 for ( const QString &name : constRenderers )
112 {
114 cboRenderers->addItem( m->icon(), m->visibleName(), name );
115 }
116
117 cboRenderers->setCurrentIndex( -1 ); // set no current renderer
118
119 connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsRendererPropertiesDialog::onOK );
120
121 // connect layer opacity slider and spin box
122 connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::rendererChanged );
123 connect( checkboxEnableOrderBy, &QAbstractButton::toggled, btnOrderBy, &QWidget::setEnabled );
124 connect( btnOrderBy, &QAbstractButton::clicked, this, &QgsRendererPropertiesDialog::showOrderByDialog );
125
126 syncToLayer();
127
128 QList<QWidget *> widgets;
129 widgets << mOpacityWidget
130 << cboRenderers
131 << checkboxEnableOrderBy
132 << mBlendModeComboBox
133 << mFeatureBlendComboBox
134 << mEffectWidget;
135
136 connectValueChanged( widgets, SIGNAL( widgetChanged() ) );
137 connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
138}
139
140void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets, const char *slot )
141{
142 for ( QWidget *widget : widgets )
143 {
144 if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
145 {
146 connect( w, SIGNAL( changed ), this, slot );
147 }
148 else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
149 {
150 connect( w, SIGNAL( fieldChanged( QString ) ), this, slot );
151 }
152 else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
153 {
154 connect( w, SIGNAL( opacityChanged( double ) ), this, slot );
155 }
156 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
157 {
158 connect( w, SIGNAL( currentIndexChanged( int ) ), this, slot );
159 }
160 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
161 {
162 connect( w, SIGNAL( valueChanged( int ) ), this, slot );
163 }
164 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
165 {
166 connect( w, SIGNAL( valueChanged( double ) ), this, slot );
167 }
168 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
169 {
170 connect( w, SIGNAL( colorChanged( QColor ) ), this, slot );
171 }
172 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
173 {
174 connect( w, SIGNAL( toggled( bool ) ), this, slot );
175 }
176 else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
177 {
178 connect( w, SIGNAL( textEdited( QString ) ), this, slot );
179 connect( w, SIGNAL( textChanged( QString ) ), this, slot );
180 }
181 else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
182 {
183 connect( w, SIGNAL( changed() ), this, slot );
184 }
185 }
186}
187
189{
190 delete mPaintEffect;
191}
192
194{
195 mMapCanvas = canvas;
196 if ( mActiveWidget )
197 {
199 context.setMapCanvas( mMapCanvas );
200 mActiveWidget->setContext( context );
201 }
202}
203
205{
206 mMapCanvas = context.mapCanvas();
207 mMessageBar = context.messageBar();
208 if ( mActiveWidget )
209 {
210 mActiveWidget->setContext( context );
211 }
212}
213
215{
216 mDockMode = dockMode;
217 mEffectWidget->setDockMode( dockMode );
218 if ( mActiveWidget )
219 mActiveWidget->setDockMode( mDockMode );
220}
221
222
224{
225 if ( cboRenderers->currentIndex() == -1 )
226 {
227 QgsDebugError( QStringLiteral( "No current item -- this should never happen!" ) );
228 return;
229 }
230
231 const QString rendererName = cboRenderers->currentData().toString();
232
233 //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
234 QgsFeatureRenderer *oldRenderer = nullptr;
236 {
237 oldRenderer = mActiveWidget->renderer()->clone();
238 }
239 else
240 {
241 oldRenderer = mLayer->renderer()->clone();
242 }
243
244 // get rid of old active widget (if any)
245 if ( mActiveWidget )
246 {
247 stackedWidget->removeWidget( mActiveWidget );
248
249 delete mActiveWidget;
250 mActiveWidget = nullptr;
251 }
252
253 QgsRendererWidget *w = nullptr;
255 if ( m )
256 w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
257 delete oldRenderer;
258
259 if ( w )
260 {
261 // instantiate the widget and set as active
262 mActiveWidget = w;
263 stackedWidget->addWidget( mActiveWidget );
264 stackedWidget->setCurrentWidget( mActiveWidget );
265 if ( mActiveWidget->renderer() )
266 {
267 if ( mMapCanvas || mMessageBar )
268 {
270 context.setMapCanvas( mMapCanvas );
271 context.setMessageBar( mMessageBar );
272 mActiveWidget->setContext( context );
273 }
276 }
279 w->setDockMode( mDockMode );
280 }
281 else
282 {
283 // set default "no edit widget available" page
284 stackedWidget->setCurrentWidget( pageNoWidget );
285 }
286}
287
289{
290 if ( !mActiveWidget || !mLayer )
291 {
292 return;
293 }
294
296
298 if ( renderer )
299 {
300 renderer->setPaintEffect( mPaintEffect->clone() );
301 // set the order by
302 renderer->setOrderBy( mOrderBy );
303 renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
304
305 mLayer->setRenderer( renderer->clone() );
306 }
307
308 // set the blend modes for the layer
309 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
310 mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
311
312 // set opacity for the layer
313 mLayer->setOpacity( mOpacityWidget->opacity() );
314}
315
317{
318 apply();
319 accept();
320}
321
323{
324 if ( mDockMode )
325 {
326 emit showPanel( panel );
327 }
328 else
329 {
330 // Show the dialog version if no one is connected
331 QDialog *dlg = new QDialog();
332 const QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
333 QgsSettings settings;
334 dlg->restoreGeometry( settings.value( key ).toByteArray() );
335 dlg->setWindowTitle( panel->panelTitle() );
336 dlg->setLayout( new QVBoxLayout() );
337 dlg->layout()->addWidget( panel );
338 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
339 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
340 dlg->layout()->addWidget( buttonBox );
341 dlg->exec();
342 settings.setValue( key, dlg->saveGeometry() );
343 panel->acceptPanel();
344 }
345}
346
347void QgsRendererPropertiesDialog::syncToLayer()
348{
349 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mLayer ) );
350 mFeatureBlendComboBox->setShowClippingModes( mBlendModeComboBox->showClippingModes() );
351
352 // Blend mode
353 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
354
355 // Feature blend mode
356 mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
357
358 // Layer opacity
359 mOpacityWidget->setOpacity( mLayer->opacity() );
360
361 //paint effect widget
362 if ( mLayer->renderer() )
363 {
364 if ( mLayer->renderer()->paintEffect() )
365 {
367 mEffectWidget->setPaintEffect( mPaintEffect );
368 }
369
371 }
372
373 // setup slot rendererChanged()
374 //setup order by
375 if ( mLayer->renderer() &&
377 {
378 checkboxEnableOrderBy->setChecked( true );
379 }
380 else
381 {
382 btnOrderBy->setEnabled( false );
383 checkboxEnableOrderBy->setChecked( false );
384 }
385
386 if ( mLayer->renderer() )
387 {
388 // set current renderer from layer
389 const QString rendererName = mLayer->renderer()->type();
390
391 const int rendererIdx = cboRenderers->findData( rendererName );
392 cboRenderers->setCurrentIndex( rendererIdx );
393
394 // no renderer found... this mustn't happen
395 Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
396 }
397
398}
399
400void QgsRendererPropertiesDialog::showOrderByDialog()
401{
402 QgsOrderByDialog dlg( mLayer, this );
403
404 dlg.setOrderBy( mOrderBy );
405 if ( dlg.exec() )
406 {
407 mOrderBy = dlg.orderBy();
408 emit widgetChanged();
409 }
410}
411
412void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
413{
414 mOrderBy = orderBy;
415 checkboxEnableOrderBy->setChecked( orderByEnabled );
416}
417
418void QgsRendererPropertiesDialog::updateUIState( bool hidden )
419{
420 mLayerRenderingGroupBox->setHidden( hidden );
421 cboRenderers->setHidden( hidden );
422}
423
424
426{
427 // Ignore the ESC key to avoid close the dialog without the properties window
428 if ( !isWindow() && e->key() == Qt::Key_Escape )
429 {
430 e->ignore();
431 }
432 else
433 {
434 QDialog::keyPressEvent( e );
435 }
436}
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QgsRendererRegistry * rendererRegistry()
Returns the application's renderer registry, used for managing vector layer renderers.
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...
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Static creation method.
void setOrderBy(const QgsFeatureRequest::OrderBy &orderBy)
Define the order in which features shall be processed by 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:142
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.
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.
The QgsFieldExpressionWidget class creates 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:194
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:93
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:84
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)
static bool layerIsContainedInGroupLayer(QgsProject *project, QgsMapLayer *layer)
Returns true if the specified layer is a child layer from any QgsGroupLayer in the given project.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:481
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.
QString visibleName() const
Returns a friendly display name of the renderer.
virtual QgsRendererWidget * createRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *oldRenderer)
Returns new instance of settings widget for 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.
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...
virtual QgsFeatureRenderer * renderer()=0
Returns pointer to the renderer (no transfer of ownership)
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:64
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 QgsDebugError(str)
Definition: qgslogger.h:38
QgsRendererWidget *(* QgsRendererWidgetFunc)(QgsVectorLayer *, QgsStyle *, QgsFeatureRenderer *)