QGIS API Documentation 3.99.0-Master (d270888f95f)
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
18#include "qgsapplication.h"
24#include "qgslogger.h"
27#include "qgsorderbydialog.h"
28#include "qgspainteffect.h"
29#include "qgspanelwidget.h"
32#include "qgsproject.h"
33#include "qgsprojectutils.h"
34#include "qgsrenderer.h"
35#include "qgsrendererregistry.h"
36#include "qgsrendererwidget.h"
39#include "qgsvectorlayer.h"
40
41#include <QKeyEvent>
42#include <QMessageBox>
43#include <QString>
44
45#include "moc_qgsrendererpropertiesdialog.cpp"
46
47using namespace Qt::StringLiterals;
48
49static bool initVectorLayerRenderer( const QString &name, QgsRendererWidgetFunc f, const QString &iconName = QString() )
50{
53 if ( !am )
54 return false;
55 QgsRendererMetadata *m = dynamic_cast<QgsRendererMetadata *>( am );
56 if ( !m )
57 return false;
58
59 m->setWidgetFunction( f );
60
61 if ( !iconName.isEmpty() )
62 {
63 m->setIcon( QgsApplication::getThemeIcon( iconName ) );
64 }
65
66 QgsDebugMsgLevel( "Set for " + name, 2 );
67 return true;
68}
69
70void QgsRendererPropertiesDialog::initRendererWidgetFunctions()
71{
72 static bool sInitialized = false;
73 if ( sInitialized )
74 return;
75
76 initVectorLayerRenderer( u"singleSymbol"_s, QgsSingleSymbolRendererWidget::create, u"rendererSingleSymbol.svg"_s );
77 initVectorLayerRenderer( u"categorizedSymbol"_s, QgsCategorizedSymbolRendererWidget::create, u"rendererCategorizedSymbol.svg"_s );
78 initVectorLayerRenderer( u"graduatedSymbol"_s, QgsGraduatedSymbolRendererWidget::create, u"rendererGraduatedSymbol.svg"_s );
79 initVectorLayerRenderer( u"RuleRenderer"_s, QgsRuleBasedRendererWidget::create, u"rendererRuleBasedSymbol.svg"_s );
80 initVectorLayerRenderer( u"pointDisplacement"_s, QgsPointDisplacementRendererWidget::create, u"rendererPointDisplacementSymbol.svg"_s );
81 initVectorLayerRenderer( u"pointCluster"_s, QgsPointClusterRendererWidget::create, u"rendererPointClusterSymbol.svg"_s );
82 initVectorLayerRenderer( u"invertedPolygonRenderer"_s, QgsInvertedPolygonRendererWidget::create, u"rendererInvertedSymbol.svg"_s );
83 initVectorLayerRenderer( u"mergedFeatureRenderer"_s, QgsMergedFeatureRendererWidget::create, u"rendererMergedFeatures.svg"_s );
84 initVectorLayerRenderer( u"heatmapRenderer"_s, QgsHeatmapRendererWidget::create, u"rendererHeatmapSymbol.svg"_s );
85 initVectorLayerRenderer( u"25dRenderer"_s, Qgs25DRendererWidget::create, u"renderer25dSymbol.svg"_s );
86 initVectorLayerRenderer( u"nullSymbol"_s, QgsNullSymbolRendererWidget::create, u"rendererNullSymbol.svg"_s );
87 initVectorLayerRenderer( u"embeddedSymbol"_s, QgsEmbeddedSymbolRendererWidget::create );
88 sInitialized = true;
89}
90
92 : QDialog( parent )
93 , mLayer( layer )
94 , mStyle( style )
95
96{
97 setupUi( this );
99 mLayerRenderingGroupBox->setSettingGroup( u"layerRenderingGroupBox"_s );
100
101 // can be embedded in vector layer properties
102 if ( embedded )
103 {
104 buttonBox->hide();
105 layout()->setContentsMargins( 0, 0, 0, 0 );
106 }
107
108 // initialize registry's widget functions
109 initRendererWidgetFunctions();
110
112 const QStringList renderers = reg->renderersList( mLayer );
113 const auto constRenderers = renderers;
114 for ( const QString &name : constRenderers )
115 {
117 cboRenderers->addItem( m->icon(), m->visibleName(), name );
118 }
119
120 cboRenderers->setCurrentIndex( -1 ); // set no current renderer
121
122 connect( buttonBox, &QDialogButtonBox::accepted, this, &QgsRendererPropertiesDialog::onOK );
123
124 // connect layer opacity slider and spin box
125 connect( cboRenderers, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::rendererChanged );
126 connect( checkboxEnableOrderBy, &QAbstractButton::toggled, btnOrderBy, &QWidget::setEnabled );
127 connect( btnOrderBy, &QAbstractButton::clicked, this, &QgsRendererPropertiesDialog::showOrderByDialog );
128
129 syncToLayer();
130
131 QList<QWidget *> widgets;
132 widgets << mOpacityWidget
133 << cboRenderers
134 << checkboxEnableOrderBy
135 << mBlendModeComboBox
136 << mFeatureBlendComboBox
137 << mEffectWidget;
138
139 connectValueChanged( widgets );
140 connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
141}
142
143void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets )
144{
145 for ( QWidget *widget : widgets )
146 {
147 if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
148 {
150 }
151 else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
152 {
153 connect( w, qOverload<const QString &>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
154 }
155 else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
156 {
158 }
159 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
160 {
161 connect( w, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
162 }
163 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
164 {
165 connect( w, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
166 }
167 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
168 {
169 connect( w, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
170 }
171 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
172 {
174 }
175 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
176 {
177 connect( w, &QCheckBox::toggled, this, &QgsRendererPropertiesDialog::widgetChanged );
178 }
179 else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
180 {
181 connect( w, &QLineEdit::textEdited, this, &QgsRendererPropertiesDialog::widgetChanged );
182 connect( w, &QLineEdit::textChanged, this, &QgsRendererPropertiesDialog::widgetChanged );
183 }
184 else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
185 {
187 }
188 }
189}
190
195
197{
198 mMapCanvas = canvas;
199 if ( mActiveWidget )
200 {
202 context.setMapCanvas( mMapCanvas );
203 mActiveWidget->setContext( context );
204 }
205}
206
208{
209 mMapCanvas = context.mapCanvas();
210 mMessageBar = context.messageBar();
211 if ( mActiveWidget )
212 {
213 mActiveWidget->setContext( context );
214 }
215}
216
218{
219 mDockMode = dockMode;
220 mEffectWidget->setDockMode( dockMode );
221 if ( mActiveWidget )
222 mActiveWidget->setDockMode( mDockMode );
223}
224
225
227{
228 if ( cboRenderers->currentIndex() == -1 )
229 {
230 QgsDebugError( u"No current item -- this should never happen!"_s );
231 return;
232 }
233
234 const QString rendererName = cboRenderers->currentData().toString();
235
236 //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
237 QgsFeatureRenderer *oldRenderer = nullptr;
238 if ( mActiveWidget && mActiveWidget->renderer() )
239 {
240 oldRenderer = mActiveWidget->renderer()->clone();
241 }
242 else
243 {
244 oldRenderer = mLayer->renderer()->clone();
245 }
246
247 // get rid of old active widget (if any)
248 if ( mActiveWidget )
249 {
250 stackedWidget->removeWidget( mActiveWidget );
251
252 delete mActiveWidget;
253 mActiveWidget = nullptr;
254 }
255
256 QgsRendererWidget *w = nullptr;
258 if ( m )
259 w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
260 delete oldRenderer;
261
262 if ( w )
263 {
264 // instantiate the widget and set as active
265 mActiveWidget = w;
266 stackedWidget->addWidget( mActiveWidget );
267 stackedWidget->setCurrentWidget( mActiveWidget );
268 if ( mActiveWidget->renderer() )
269 {
270 if ( mMapCanvas || mMessageBar )
271 {
273 context.setMapCanvas( mMapCanvas );
274 context.setMessageBar( mMessageBar );
275 mActiveWidget->setContext( context );
276 }
277 changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
279 }
282 w->setDockMode( mDockMode );
283 }
284 else
285 {
286 // set default "no edit widget available" page
287 stackedWidget->setCurrentWidget( pageNoWidget );
288 }
289}
290
292{
293 if ( !mActiveWidget || !mLayer )
294 {
295 return;
296 }
297
298 mActiveWidget->applyChanges();
299
300 QgsFeatureRenderer *renderer = mActiveWidget->renderer();
301 if ( renderer )
302 {
303 renderer->setPaintEffect( mPaintEffect->clone() );
304 // set the order by
305 renderer->setOrderBy( mOrderBy );
306 renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
307
308 mLayer->setRenderer( renderer->clone() );
309 }
310
311 // set the blend modes for the layer
312 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
313 mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
314
315 // set opacity for the layer
316 mLayer->setOpacity( mOpacityWidget->opacity() );
317}
318
320{
321 apply();
322 accept();
323}
324
326{
327 if ( mDockMode )
328 {
329 emit showPanel( panel );
330 }
331 else
332 {
333 // Show the dialog version if no one is connected
334 QDialog *dlg = new QDialog();
335 const QString key = u"/UI/paneldialog/%1"_s.arg( panel->panelTitle() );
336 QgsSettings settings;
337 dlg->restoreGeometry( settings.value( key ).toByteArray() );
338 dlg->setWindowTitle( panel->panelTitle() );
339 dlg->setLayout( new QVBoxLayout() );
340 dlg->layout()->addWidget( panel );
341 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
342 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
343 dlg->layout()->addWidget( buttonBox );
344 dlg->exec();
345 settings.setValue( key, dlg->saveGeometry() );
346 panel->acceptPanel();
347 }
348}
349
350void QgsRendererPropertiesDialog::syncToLayer()
351{
352 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mLayer ) );
353 mFeatureBlendComboBox->setShowClippingModes( mBlendModeComboBox->showClippingModes() );
354
355 // Blend mode
356 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
357
358 // Feature blend mode
359 mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
360
361 // Layer opacity
362 mOpacityWidget->setOpacity( mLayer->opacity() );
363
364 //paint effect widget
365 if ( mLayer->renderer() )
366 {
367 if ( mLayer->renderer()->paintEffect() )
368 {
370 mEffectWidget->setPaintEffect( mPaintEffect );
371 }
372
373 mOrderBy = mLayer->renderer()->orderBy();
374 }
375
376 // setup slot rendererChanged()
377 //setup order by
378 if ( mLayer->renderer() && mLayer->renderer()->orderByEnabled() )
379 {
380 checkboxEnableOrderBy->setChecked( true );
381 }
382 else
383 {
384 btnOrderBy->setEnabled( false );
385 checkboxEnableOrderBy->setChecked( false );
386 }
387
388 if ( mLayer->renderer() )
389 {
390 // set current renderer from layer
391 const QString rendererName = mLayer->renderer()->type();
392
393 const int rendererIdx = cboRenderers->findData( rendererName );
394 cboRenderers->setCurrentIndex( rendererIdx );
395
396 // no renderer found... this mustn't happen
397 Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
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.
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.
A widget for selection of layer fields or expression creation.
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:224
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.
QPainter::CompositionMode blendMode() const
Returns the current blending mode for a layer.
double opacity
Definition qgsmaplayer.h:95
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....
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 an inline panel.
QString panelTitle() const
The title of the panel.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
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.
static QgsRendererWidget * create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)
Stores settings for use within QGIS.
Definition qgssettings.h:68
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)
A database of saved style entities, including symbols, color ramps, text formats and others.
Definition qgsstyle.h:89
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 dataset.
QPainter::CompositionMode featureBlendMode() const
Returns the current blending mode for features.
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:63
#define QgsDebugError(str)
Definition qgslogger.h:59
QgsRendererWidget *(* QgsRendererWidgetFunc)(QgsVectorLayer *, QgsStyle *, QgsFeatureRenderer *)