QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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 << cboRenderers << checkboxEnableOrderBy << mBlendModeComboBox << mFeatureBlendComboBox << mEffectWidget;
133
134 connectValueChanged( widgets );
135 connect( mEffectWidget, &QgsPanelWidget::showPanel, this, &QgsRendererPropertiesDialog::openPanel );
136}
137
138void QgsRendererPropertiesDialog::connectValueChanged( const QList<QWidget *> &widgets )
139{
140 for ( QWidget *widget : widgets )
141 {
142 if ( QgsPropertyOverrideButton *w = qobject_cast<QgsPropertyOverrideButton *>( widget ) )
143 {
145 }
146 else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
147 {
148 connect( w, qOverload<const QString &>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
149 }
150 else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
151 {
153 }
154 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
155 {
156 connect( w, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
157 }
158 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
159 {
160 connect( w, qOverload<int>( &QSpinBox::valueChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
161 }
162 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
163 {
164 connect( w, qOverload<double>( &QDoubleSpinBox::valueChanged ), this, &QgsRendererPropertiesDialog::widgetChanged );
165 }
166 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
167 {
169 }
170 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
171 {
172 connect( w, &QCheckBox::toggled, this, &QgsRendererPropertiesDialog::widgetChanged );
173 }
174 else if ( QLineEdit *w = qobject_cast<QLineEdit *>( widget ) )
175 {
176 connect( w, &QLineEdit::textEdited, this, &QgsRendererPropertiesDialog::widgetChanged );
177 connect( w, &QLineEdit::textChanged, this, &QgsRendererPropertiesDialog::widgetChanged );
178 }
179 else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
180 {
182 }
183 }
184}
185
190
192{
193 mMapCanvas = canvas;
194 if ( mActiveWidget )
195 {
197 context.setMapCanvas( mMapCanvas );
198 mActiveWidget->setContext( context );
199 }
200}
201
203{
204 mMapCanvas = context.mapCanvas();
205 mMessageBar = context.messageBar();
206 if ( mActiveWidget )
207 {
208 mActiveWidget->setContext( context );
209 }
210}
211
213{
214 mDockMode = dockMode;
215 mEffectWidget->setDockMode( dockMode );
216 if ( mActiveWidget )
217 mActiveWidget->setDockMode( mDockMode );
218}
219
220
222{
223 if ( cboRenderers->currentIndex() == -1 )
224 {
225 QgsDebugError( u"No current item -- this should never happen!"_s );
226 return;
227 }
228
229 const QString rendererName = cboRenderers->currentData().toString();
230
231 //Retrieve the previous renderer: from the old active widget if possible, otherwise from the layer
232 QgsFeatureRenderer *oldRenderer = nullptr;
233 if ( mActiveWidget && mActiveWidget->renderer() )
234 {
235 oldRenderer = mActiveWidget->renderer()->clone();
236 }
237 else
238 {
239 oldRenderer = mLayer->renderer()->clone();
240 }
241
242 // get rid of old active widget (if any)
243 if ( mActiveWidget )
244 {
245 stackedWidget->removeWidget( mActiveWidget );
246
247 delete mActiveWidget;
248 mActiveWidget = nullptr;
249 }
250
251 QgsRendererWidget *w = nullptr;
253 if ( m )
254 w = m->createRendererWidget( mLayer, mStyle, oldRenderer );
255 delete oldRenderer;
256
257 if ( w )
258 {
259 // instantiate the widget and set as active
260 mActiveWidget = w;
261 stackedWidget->addWidget( mActiveWidget );
262 stackedWidget->setCurrentWidget( mActiveWidget );
263 if ( mActiveWidget->renderer() )
264 {
265 if ( mMapCanvas || mMessageBar )
266 {
268 context.setMapCanvas( mMapCanvas );
269 context.setMessageBar( mMessageBar );
270 mActiveWidget->setContext( context );
271 }
272 changeOrderBy( mActiveWidget->renderer()->orderBy(), mActiveWidget->renderer()->orderByEnabled() );
274 }
277 w->setDockMode( mDockMode );
278 }
279 else
280 {
281 // set default "no edit widget available" page
282 stackedWidget->setCurrentWidget( pageNoWidget );
283 }
284}
285
287{
288 if ( !mActiveWidget || !mLayer )
289 {
290 return;
291 }
292
293 mActiveWidget->applyChanges();
294
295 QgsFeatureRenderer *renderer = mActiveWidget->renderer();
296 if ( renderer )
297 {
298 renderer->setPaintEffect( mPaintEffect->clone() );
299 // set the order by
300 renderer->setOrderBy( mOrderBy );
301 renderer->setOrderByEnabled( checkboxEnableOrderBy->isChecked() );
302
303 mLayer->setRenderer( renderer->clone() );
304 }
305
306 // set the blend modes for the layer
307 mLayer->setBlendMode( mBlendModeComboBox->blendMode() );
308 mLayer->setFeatureBlendMode( mFeatureBlendComboBox->blendMode() );
309
310 // set opacity for the layer
311 mLayer->setOpacity( mOpacityWidget->opacity() );
312}
313
315{
316 apply();
317 accept();
318}
319
321{
322 if ( mDockMode )
323 {
324 emit showPanel( panel );
325 }
326 else
327 {
328 // Show the dialog version if no one is connected
329 QDialog *dlg = new QDialog();
330 const QString key = u"/UI/paneldialog/%1"_s.arg( panel->panelTitle() );
331 QgsSettings settings;
332 dlg->restoreGeometry( settings.value( key ).toByteArray() );
333 dlg->setWindowTitle( panel->panelTitle() );
334 dlg->setLayout( new QVBoxLayout() );
335 dlg->layout()->addWidget( panel );
336 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
337 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
338 dlg->layout()->addWidget( buttonBox );
339 dlg->exec();
340 settings.setValue( key, dlg->saveGeometry() );
341 panel->acceptPanel();
342 }
343}
344
345void QgsRendererPropertiesDialog::syncToLayer()
346{
347 mBlendModeComboBox->setShowClippingModes( QgsProjectUtils::layerIsContainedInGroupLayer( QgsProject::instance(), mLayer ) );
348 mFeatureBlendComboBox->setShowClippingModes( mBlendModeComboBox->showClippingModes() );
349
350 // Blend mode
351 mBlendModeComboBox->setBlendMode( mLayer->blendMode() );
352
353 // Feature blend mode
354 mFeatureBlendComboBox->setBlendMode( mLayer->featureBlendMode() );
355
356 // Layer opacity
357 mOpacityWidget->setOpacity( mLayer->opacity() );
358
359 //paint effect widget
360 if ( mLayer->renderer() )
361 {
362 if ( mLayer->renderer()->paintEffect() )
363 {
365 mEffectWidget->setPaintEffect( mPaintEffect );
366 }
367
368 mOrderBy = mLayer->renderer()->orderBy();
369 }
370
371 // setup slot rendererChanged()
372 //setup order by
373 if ( mLayer->renderer() && mLayer->renderer()->orderByEnabled() )
374 {
375 checkboxEnableOrderBy->setChecked( true );
376 }
377 else
378 {
379 btnOrderBy->setEnabled( false );
380 checkboxEnableOrderBy->setChecked( false );
381 }
382
383 if ( mLayer->renderer() )
384 {
385 // set current renderer from layer
386 const QString rendererName = mLayer->renderer()->type();
387
388 const int rendererIdx = cboRenderers->findData( rendererName );
389 cboRenderers->setCurrentIndex( rendererIdx );
390
391 // no renderer found... this mustn't happen
392 Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
393 }
394}
395
396void QgsRendererPropertiesDialog::showOrderByDialog()
397{
398 QgsOrderByDialog dlg( mLayer, this );
399
400 dlg.setOrderBy( mOrderBy );
401 if ( dlg.exec() )
402 {
403 mOrderBy = dlg.orderBy();
404 emit widgetChanged();
405 }
406}
407
408void QgsRendererPropertiesDialog::changeOrderBy( const QgsFeatureRequest::OrderBy &orderBy, bool orderByEnabled )
409{
410 mOrderBy = orderBy;
411 checkboxEnableOrderBy->setChecked( orderByEnabled );
412}
413
414void QgsRendererPropertiesDialog::updateUIState( bool hidden )
415{
416 mLayerRenderingGroupBox->setHidden( hidden );
417 cboRenderers->setHidden( hidden );
418}
419
420
422{
423 // Ignore the ESC key to avoid close the dialog without the properties window
424 if ( !isWindow() && e->key() == Qt::Key_Escape )
425 {
426 e->ignore();
427 }
428 else
429 {
430 QDialog::keyPressEvent( e );
431 }
432}
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 *)