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