QGIS API Documentation 3.99.0-Master (21b3aa880ba)
Loading...
Searching...
No Matches
qgslabelingwidget.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslabelingwidget.cpp
3 ---------------------
4 begin : September 2015
5 copyright : (C) 2015 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 ***************************************************************************/
15
16#include "qgslabelingwidget.h"
17
18#include <memory>
19
20#include "qgsapplication.h"
23#include "qgslabelinggui.h"
25#include "qgsmapcanvas.h"
26#include "qgsproject.h"
28#include "qgsvectorlayer.h"
30
31#include <QDialogButtonBox>
32#include <QDomElement>
33
34#include "moc_qgslabelingwidget.cpp"
35
36QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent, QgsMessageBar *messageBar )
37 : QgsMapLayerConfigWidget( layer, canvas, parent )
38 , mLayer( layer )
39 , mCanvas( canvas )
40 , mMessageBar( messageBar )
41
42{
43 setupUi( this );
44
45 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingNone.svg" ) ), tr( "No Labels" ), ModeNone );
46 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ), tr( "Single Labels" ), ModeSingle );
47 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingRuleBased.svg" ) ), tr( "Rule-based Labeling" ), ModeRuleBased );
48 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingObstacle.svg" ) ), tr( "Blocking" ), ModeBlocking );
49
50 connect( mLabelRulesButton, &QAbstractButton::clicked, this, &QgsLabelingWidget::showLabelingEngineRulesPrivate );
51 connect( mEngineSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingWidget::showEngineConfigDialogPrivate );
52
53 connect( mLabelModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingWidget::labelModeChanged );
54 setLayer( layer );
55
56 const int iconSize16 = QgsGuiUtils::scaleIconSize( 16 );
57 mEngineSettingsButton->setIconSize( QSize( iconSize16, iconSize16 ) );
58 mLabelRulesButton->setIconSize( QSize( iconSize16, iconSize16 ) );
59}
60
62{
63 return qobject_cast<QgsLabelingGui *>( mWidget );
64}
65
67{
68 if ( mOldSettings )
69 {
70 mLayer->setLabeling( mOldSettings.release() );
71 mLayer->setLabelsEnabled( mOldLabelsEnabled );
72 }
73 setLayer( mLayer );
74}
75
76
78{
79 if ( !mapLayer || mapLayer->type() != Qgis::LayerType::Vector )
80 {
81 setEnabled( false );
82 return;
83 }
84 else
85 {
86 setEnabled( true );
87 }
88
89 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mapLayer );
90 mLayer = layer;
91 if ( mLayer->labeling() )
92 {
93 mOldSettings.reset( mLayer->labeling()->clone() );
94 }
95 else
96 mOldSettings.reset();
97 mOldLabelsEnabled = mLayer->labelsEnabled();
98
100}
101
103{
104 if ( !mLayer )
105 return;
106
107 whileBlocking( mLabelModeComboBox )->setCurrentIndex( -1 );
108
109 // pick the right mode of the layer
110 if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == QLatin1String( "rule-based" ) )
111 {
112 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeRuleBased ) );
113 }
114 else if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == QLatin1String( "simple" ) )
115 {
116 const QgsPalLayerSettings lyr = mLayer->labeling()->settings();
117
118 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( lyr.drawLabels ? ModeSingle : ModeBlocking ) );
119 }
120 else
121 {
122 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeNone ) );
123 }
124
125 if ( QgsLabelingGui *lg = qobject_cast<QgsLabelingGui *>( mWidget ) )
126 {
127 lg->updateUi();
128 }
129}
130
132{
133 const Mode mode = static_cast<Mode>( mLabelModeComboBox->currentData().toInt() );
134 switch ( mode )
135 {
136 case ModeRuleBased:
137 {
138 const QgsRuleBasedLabeling::Rule *rootRule = qobject_cast<QgsRuleBasedLabelingWidget *>( mWidget )->rootRule();
139 mLayer->setLabeling( new QgsRuleBasedLabeling( rootRule->clone( false ) ) );
140 mLayer->setLabelsEnabled( true );
141 break;
142 }
143
144 case ModeSingle:
145 {
146 mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( qobject_cast<QgsLabelingGui *>( mWidget )->layerSettings() ) );
147 mLayer->setLabelsEnabled( true );
148 break;
149 }
150
151 case ModeBlocking:
152 {
153 mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( *mSimpleSettings ) );
154 mLayer->setLabelsEnabled( true );
155 break;
156 }
157
158 case ModeNone:
159 {
160 mLayer->setLabelsEnabled( false );
161 break;
162 }
163 }
164}
165
167{
170 // trigger refresh
171 mLayer->triggerRepaint();
172}
173
174void QgsLabelingWidget::labelModeChanged( int index )
175{
176 if ( mWidget )
177 mStackedWidget->removeWidget( mWidget );
178
179 delete mWidget;
180 mWidget = nullptr;
181
182 if ( index < 0 )
183 return;
184
185 const Mode mode = static_cast<Mode>( mLabelModeComboBox->currentData().toInt() );
186
187 switch ( mode )
188 {
189 case ModeRuleBased:
190 {
191 // note - QgsRuleBasedLabelingWidget handles conversion of existing non-rule based labels to rule based
192 QgsRuleBasedLabelingWidget *ruleWidget = new QgsRuleBasedLabelingWidget( mLayer, mCanvas, this );
193 ruleWidget->setDockMode( dockMode() );
194 connect( ruleWidget, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
196 mWidget = ruleWidget;
197 mStackedWidget->addWidget( mWidget );
198 mStackedWidget->setCurrentWidget( mWidget );
199 break;
200 }
201
202 case ModeSingle:
203 case ModeBlocking:
204 {
205 mSimpleSettings.reset();
206 if ( mLayer->labeling() && mLayer->labeling()->type() == QLatin1String( "simple" ) )
207 {
208 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( mLayer->labeling()->settings() );
209 }
210 else if ( mLayer->labeling() && mLayer->labeling()->type() == QLatin1String( "rule-based" ) )
211 {
212 // changing from rule-based to simple labels... grab first rule, and copy settings
213 const QgsRuleBasedLabeling *rl = static_cast<const QgsRuleBasedLabeling *>( mLayer->labeling() );
214 if ( const QgsRuleBasedLabeling::Rule *rootRule = rl->rootRule() )
215 {
216 if ( const QgsRuleBasedLabeling::Rule *firstChild = rootRule->children().value( 0 ) )
217 {
218 if ( firstChild->settings() )
219 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( *firstChild->settings() );
220 }
221 }
222 }
223
224 if ( !mSimpleSettings )
225 {
226 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( QgsAbstractVectorLayerLabeling::defaultSettingsForLayer( mLayer ) );
227 }
228
229 if ( mSimpleSettings->fieldName.isEmpty() )
230 mSimpleSettings->fieldName = mLayer->displayField();
231
232 QgsSymbolWidgetContext context;
233 context.setMapCanvas( mMapCanvas );
234 context.setMessageBar( mMessageBar );
235
236 switch ( mode )
237 {
238 case ModeSingle:
239 {
240 QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
241 simpleWidget->setContext( context );
242
243 simpleWidget->setDockMode( dockMode() );
245 connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
246
247 simpleWidget->setLabelMode( QgsLabelingGui::Labels );
248
249 mWidget = simpleWidget;
250 break;
251 }
252 case ModeBlocking:
253 {
254 QgsLabelObstacleSettingsWidget *obstacleWidget = new QgsLabelObstacleSettingsWidget( this, mLayer );
255 obstacleWidget->setContext( context );
256 obstacleWidget->setGeometryType( mLayer ? mLayer->geometryType() : Qgis::GeometryType::Unknown );
257 obstacleWidget->setDockMode( dockMode() );
258 obstacleWidget->setSettings( mSimpleSettings->obstacleSettings() );
259 obstacleWidget->setDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
260
261 mSimpleSettings->obstacleSettings().setIsObstacle( true );
262 mSimpleSettings->drawLabels = false;
263
264 connect( obstacleWidget, &QgsLabelSettingsWidgetBase::changed, this, [this, obstacleWidget] {
265 mSimpleSettings->setObstacleSettings( obstacleWidget->settings() );
266 obstacleWidget->updateDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
267 emit widgetChanged();
268 } );
270
271 mWidget = obstacleWidget;
272 break;
273 }
274
275 case ModeRuleBased:
276 case ModeNone:
277 break;
278 }
279
280 mStackedWidget->addWidget( mWidget );
281 mStackedWidget->setCurrentWidget( mWidget );
282 break;
283 }
284
285 case ModeNone:
286 break;
287 }
288 emit widgetChanged();
289}
290
291
293{
296 QList<QgsAbstractLabelingEngineRule *> rules;
297 for ( const QgsAbstractLabelingEngineRule *rule : settings.rules() )
298 {
299 // blame sip, it requires the widget setter to take non-const pointers?!
300 rules << const_cast<QgsAbstractLabelingEngineRule *>( rule );
301 }
302 if ( panel && panel->dockMode() )
303 {
305 widget->setRules( rules );
306 connect( widget, &QgsLabelingEngineRulesWidget::changed, widget, [widget, canvas] {
308 settings.setRules( widget->rules() );
311 if ( canvas )
312 canvas->refreshAllLayers();
313 } );
314 panel->openPanel( widget );
315 }
316 else
317 {
318 QgsLabelingEngineRulesDialog dialog( parent );
319 dialog.setRules( rules );
320 if ( dialog.exec() )
321 {
323 settings.setRules( dialog.rules() );
326 if ( canvas )
327 canvas->refreshAllLayers();
328 }
329 parent->activateWindow();
330 }
331}
332
333void QgsLabelingWidget::showLabelingEngineRulesPrivate()
334{
335 showLabelingEngineRules( this, mCanvas );
336}
337
339{
341 if ( panel && panel->dockMode() )
342 {
345 panel->openPanel( widget );
346 }
347 else
348 {
349 QgsLabelEngineConfigDialog dialog( canvas, parent );
350 dialog.exec();
351 // reactivate button's window
352 parent->activateWindow();
353 }
354}
355
356void QgsLabelingWidget::showEngineConfigDialogPrivate()
357{
358 showEngineConfiguration( this, mCanvas );
359}
@ Unknown
Unknown types.
Definition qgis.h:362
@ Vector
Vector layer.
Definition qgis.h:191
Abstract base class for labeling engine rules.
static QgsPalLayerSettings defaultSettingsForLayer(const QgsVectorLayer *layer)
Returns the default layer settings to use for the specified vector layer.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
Dialog for configuring the labeling engine.
Widget for configuring the labeling engine.
void setGeometryType(Qgis::GeometryType type) override
Sets the geometry type of the features to customize the widget accordingly.
QgsLabelObstacleSettings settings() const
Returns the obstacle settings defined by the widget.
void updateDataDefinedProperties(QgsPropertyCollection &properties) override
Updates a data defined properties collection, correctly setting the values for any properties related...
void setSettings(const QgsLabelObstacleSettings &settings)
Sets the obstacle settings to show in the widget.
void changed()
Emitted when any of the settings described by the widget are changed.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created in the widget.
void setDataDefinedProperties(const QgsPropertyCollection &dataDefinedProperties)
Sets the current data defined properties to show in the widget.
A dialog which allows configuration of a list of labeling engine rules.
QList< QgsAbstractLabelingEngineRule * > rules() const
Returns the rules shown in the dialog.
void setRules(const QList< QgsAbstractLabelingEngineRule * > &rules)
Sets the rules to show in the dialog.
A widget which allows configuration of a list of labeling engine rules.
void setRules(const QList< QgsAbstractLabelingEngineRule * > &rules)
Sets the rules to show in the widget.
QList< QgsAbstractLabelingEngineRule * > rules() const
Returns the rules shown in the widget.
void changed()
Emitted when the rules configured in the widget are changed.
Stores global configuration for labeling engine.
void setRules(const QList< QgsAbstractLabelingEngineRule * > &rules)
Sets the labeling engine rules which must be satisfied while placing labels.
QList< QgsAbstractLabelingEngineRule * > rules()
Returns a list of labeling engine rules which must be satisfied while placing labels.
void adaptToLayer()
reload the settings shown in the dialog from the current layer
QgsLabelingGui * labelingGui()
Returns the labeling gui widget or nullptr if none.
static void showLabelingEngineRules(QWidget *parent, QgsMapCanvas *canvas)
Shows the labeling engine rules.
QgsLabelingWidget(QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr, QgsMessageBar *messageBar=nullptr)
constructor
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created.
void apply() override
Saves the labeling configuration and immediately updates the map canvas to reflect the changes.
void writeSettingsToLayer()
save config to layer
void resetSettings()
Reset the settings.
void setLayer(QgsMapLayer *layer)
Sets the layer to configure.
static void showEngineConfiguration(QWidget *parent, QgsMapCanvas *canvas)
Shows the labeling engine configuration.
Map canvas is a class for displaying all GIS data types on a canvas.
void refreshAllLayers()
Reload all layers (including refreshing layer properties from their data sources),...
QgsMapLayerConfigWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
A panel widget that can be shown in the map style dock.
Base class for all map layer types.
Definition qgsmaplayer.h:80
Qgis::LayerType type
Definition qgsmaplayer.h:90
A bar for displaying non-blocking messages to the user.
Contains settings for how a map layer will be labeled.
bool drawLabels
Whether to draw labels for this layer.
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 ...
bool dockMode() const
Returns the dock mode state.
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
void widgetChanged()
Emitted when the widget state changes.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets project's global labeling engine settings.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns project's global labeling engine settings.
void setDirty(bool b=true)
Flag the project as dirty (modified).
Widget for configuring rule based labeling.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
A child rule for QgsRuleBasedLabeling.
QgsRuleBasedLabeling::Rule * clone(bool resetRuleKey=true) const
clone this rule
Rule based labeling for a vector layer.
QgsRuleBasedLabeling::Rule * rootRule()
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void widgetChanged()
Emitted when the text format defined by the widget changes.
Basic implementation of the labeling interface.
Represents a vector layer which manages a vector based dataset.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6511