QGIS API Documentation 3.99.0-Master (d270888f95f)
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#include <QString>
34
35#include "moc_qgslabelingwidget.cpp"
36
37using namespace Qt::StringLiterals;
38
39QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent, QgsMessageBar *messageBar )
40 : QgsMapLayerConfigWidget( layer, canvas, parent )
41 , mLayer( layer )
42 , mCanvas( canvas )
43 , mMessageBar( messageBar )
44
45{
46 setupUi( this );
47
48 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( u"labelingNone.svg"_s ), tr( "No Labels" ), ModeNone );
49 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( u"labelingSingle.svg"_s ), tr( "Single Labels" ), ModeSingle );
50 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( u"labelingRuleBased.svg"_s ), tr( "Rule-based Labeling" ), ModeRuleBased );
51 mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( u"labelingObstacle.svg"_s ), tr( "Blocking" ), ModeBlocking );
52
53 connect( mLabelRulesButton, &QAbstractButton::clicked, this, &QgsLabelingWidget::showLabelingEngineRulesPrivate );
54 connect( mEngineSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingWidget::showEngineConfigDialogPrivate );
55
56 connect( mLabelModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingWidget::labelModeChanged );
57 setLayer( layer );
58
59 const int iconSize16 = QgsGuiUtils::scaleIconSize( 16 );
60 mEngineSettingsButton->setIconSize( QSize( iconSize16, iconSize16 ) );
61 mLabelRulesButton->setIconSize( QSize( iconSize16, iconSize16 ) );
62}
63
65{
66 return qobject_cast<QgsLabelingGui *>( mWidget );
67}
68
70{
71 if ( mOldSettings )
72 {
73 mLayer->setLabeling( mOldSettings.release() );
74 mLayer->setLabelsEnabled( mOldLabelsEnabled );
75 }
76 setLayer( mLayer );
77}
78
79
81{
82 if ( !mapLayer || mapLayer->type() != Qgis::LayerType::Vector )
83 {
84 setEnabled( false );
85 return;
86 }
87 else
88 {
89 setEnabled( true );
90 }
91
92 QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mapLayer );
93 mLayer = layer;
94 if ( mLayer->labeling() )
95 {
96 mOldSettings.reset( mLayer->labeling()->clone() );
97 }
98 else
99 mOldSettings.reset();
100 mOldLabelsEnabled = mLayer->labelsEnabled();
101
102 adaptToLayer();
103}
104
106{
107 if ( !mLayer )
108 return;
109
110 whileBlocking( mLabelModeComboBox )->setCurrentIndex( -1 );
111
112 // pick the right mode of the layer
113 if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == "rule-based"_L1 )
114 {
115 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeRuleBased ) );
116 }
117 else if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == "simple"_L1 )
118 {
119 const QgsPalLayerSettings lyr = mLayer->labeling()->settings();
120
121 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( lyr.drawLabels ? ModeSingle : ModeBlocking ) );
122 }
123 else
124 {
125 mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeNone ) );
126 }
127
128 if ( QgsLabelingGui *lg = qobject_cast<QgsLabelingGui *>( mWidget ) )
129 {
130 lg->updateUi();
131 }
132}
133
135{
136 const Mode mode = static_cast<Mode>( mLabelModeComboBox->currentData().toInt() );
137 switch ( mode )
138 {
139 case ModeRuleBased:
140 {
141 const QgsRuleBasedLabeling::Rule *rootRule = qobject_cast<QgsRuleBasedLabelingWidget *>( mWidget )->rootRule();
142 mLayer->setLabeling( new QgsRuleBasedLabeling( rootRule->clone( false ) ) );
143 mLayer->setLabelsEnabled( true );
144 break;
145 }
146
147 case ModeSingle:
148 {
149 mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( qobject_cast<QgsLabelingGui *>( mWidget )->layerSettings() ) );
150 mLayer->setLabelsEnabled( true );
151 break;
152 }
153
154 case ModeBlocking:
155 {
156 mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( *mSimpleSettings ) );
157 mLayer->setLabelsEnabled( true );
158 break;
159 }
160
161 case ModeNone:
162 {
163 mLayer->setLabelsEnabled( false );
164 break;
165 }
166 }
167}
168
170{
173 // trigger refresh
174 mLayer->triggerRepaint();
175}
176
177void QgsLabelingWidget::labelModeChanged( int index )
178{
179 if ( mWidget )
180 mStackedWidget->removeWidget( mWidget );
181
182 delete mWidget;
183 mWidget = nullptr;
184
185 if ( index < 0 )
186 return;
187
188 const Mode mode = static_cast<Mode>( mLabelModeComboBox->currentData().toInt() );
189
190 switch ( mode )
191 {
192 case ModeRuleBased:
193 {
194 // note - QgsRuleBasedLabelingWidget handles conversion of existing non-rule based labels to rule based
195 QgsRuleBasedLabelingWidget *ruleWidget = new QgsRuleBasedLabelingWidget( mLayer, mCanvas, this );
196 ruleWidget->setDockMode( dockMode() );
197 connect( ruleWidget, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
199 mWidget = ruleWidget;
200 mStackedWidget->addWidget( mWidget );
201 mStackedWidget->setCurrentWidget( mWidget );
202 break;
203 }
204
205 case ModeSingle:
206 case ModeBlocking:
207 {
208 mSimpleSettings.reset();
209 if ( mLayer->labeling() && mLayer->labeling()->type() == "simple"_L1 )
210 {
211 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( mLayer->labeling()->settings() );
212 }
213 else if ( mLayer->labeling() && mLayer->labeling()->type() == "rule-based"_L1 )
214 {
215 // changing from rule-based to simple labels... grab first rule, and copy settings
216 const QgsRuleBasedLabeling *rl = static_cast<const QgsRuleBasedLabeling *>( mLayer->labeling() );
217 if ( const QgsRuleBasedLabeling::Rule *rootRule = rl->rootRule() )
218 {
219 if ( const QgsRuleBasedLabeling::Rule *firstChild = rootRule->children().value( 0 ) )
220 {
221 if ( firstChild->settings() )
222 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( *firstChild->settings() );
223 }
224 }
225 }
226
227 if ( !mSimpleSettings )
228 {
229 mSimpleSettings = std::make_unique<QgsPalLayerSettings>( QgsAbstractVectorLayerLabeling::defaultSettingsForLayer( mLayer ) );
230 }
231
232 if ( mSimpleSettings->fieldName.isEmpty() )
233 mSimpleSettings->fieldName = mLayer->displayField();
234
235 QgsSymbolWidgetContext context;
236 context.setMapCanvas( mMapCanvas );
237 context.setMessageBar( mMessageBar );
238
239 switch ( mode )
240 {
241 case ModeSingle:
242 {
243 QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
244 simpleWidget->setContext( context );
245
246 simpleWidget->setDockMode( dockMode() );
248 connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
249
250 simpleWidget->setLabelMode( QgsLabelingGui::Labels );
251
252 mWidget = simpleWidget;
253 break;
254 }
255 case ModeBlocking:
256 {
257 QgsLabelObstacleSettingsWidget *obstacleWidget = new QgsLabelObstacleSettingsWidget( this, mLayer );
258 obstacleWidget->setContext( context );
259 obstacleWidget->setGeometryType( mLayer ? mLayer->geometryType() : Qgis::GeometryType::Unknown );
260 obstacleWidget->setDockMode( dockMode() );
261 obstacleWidget->setSettings( mSimpleSettings->obstacleSettings() );
262 obstacleWidget->setDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
263
264 mSimpleSettings->obstacleSettings().setIsObstacle( true );
265 mSimpleSettings->drawLabels = false;
266
267 connect( obstacleWidget, &QgsLabelSettingsWidgetBase::changed, this, [this, obstacleWidget] {
268 mSimpleSettings->setObstacleSettings( obstacleWidget->settings() );
269 obstacleWidget->updateDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
270 emit widgetChanged();
271 } );
273
274 mWidget = obstacleWidget;
275 break;
276 }
277
278 case ModeRuleBased:
279 case ModeNone:
280 break;
281 }
282
283 mStackedWidget->addWidget( mWidget );
284 mStackedWidget->setCurrentWidget( mWidget );
285 break;
286 }
287
288 case ModeNone:
289 break;
290 }
291 emit widgetChanged();
292}
293
294
296{
299 QList<QgsAbstractLabelingEngineRule *> rules;
300 for ( const QgsAbstractLabelingEngineRule *rule : settings.rules() )
301 {
302 // blame sip, it requires the widget setter to take non-const pointers?!
303 rules << const_cast<QgsAbstractLabelingEngineRule *>( rule );
304 }
305 if ( panel && panel->dockMode() )
306 {
308 widget->setRules( rules );
309 connect( widget, &QgsLabelingEngineRulesWidget::changed, widget, [widget, canvas] {
311 settings.setRules( widget->rules() );
314 if ( canvas )
315 canvas->refreshAllLayers();
316 } );
317 panel->openPanel( widget );
318 }
319 else
320 {
321 QgsLabelingEngineRulesDialog dialog( parent );
322 dialog.setRules( rules );
323 if ( dialog.exec() )
324 {
326 settings.setRules( dialog.rules() );
329 if ( canvas )
330 canvas->refreshAllLayers();
331 }
332 parent->activateWindow();
333 }
334}
335
336void QgsLabelingWidget::showLabelingEngineRulesPrivate()
337{
338 showLabelingEngineRules( this, mCanvas );
339}
340
342{
344 if ( panel && panel->dockMode() )
345 {
348 panel->openPanel( widget );
349 }
350 else
351 {
352 QgsLabelEngineConfigDialog dialog( canvas, parent );
353 dialog.exec();
354 // reactivate button's window
355 parent->activateWindow();
356 }
357}
358
359void QgsLabelingWidget::showEngineConfigDialogPrivate()
360{
361 showEngineConfiguration( this, mCanvas );
362}
@ Unknown
Unknown types.
Definition qgis.h:369
@ Vector
Vector layer.
Definition qgis.h:194
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:83
Qgis::LayerType type
Definition qgsmaplayer.h:93
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:6804