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