QGIS API Documentation  3.23.0-Master (dd0cd13a00)
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 <QDialogButtonBox>
17 #include <QDomElement>
18 
19 #include "qgslabelingwidget.h"
20 
22 #include "qgslabelinggui.h"
23 #include "qgsreadwritecontext.h"
25 #include "qgsvectorlayer.h"
26 #include "qgsvectorlayerlabeling.h"
27 #include "qgsproject.h"
28 #include "qgsapplication.h"
30 
31 QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent, QgsMessageBar *messageBar )
32  : QgsMapLayerConfigWidget( layer, canvas, parent )
33  , mLayer( layer )
34  , mCanvas( canvas )
35  , mMessageBar( messageBar )
36 
37 {
38  setupUi( this );
39 
40  mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingNone.svg" ) ), tr( "No Labels" ), ModeNone );
41  mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingSingle.svg" ) ), tr( "Single Labels" ), ModeSingle );
42  mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingRuleBased.svg" ) ), tr( "Rule-based Labeling" ), ModeRuleBased );
43  mLabelModeComboBox->addItem( QgsApplication::getThemeIcon( QStringLiteral( "labelingObstacle.svg" ) ), tr( "Blocking" ), ModeBlocking );
44 
45  connect( mEngineSettingsButton, &QAbstractButton::clicked, this, &QgsLabelingWidget::showEngineConfigDialog );
46 
47  connect( mLabelModeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelingWidget::labelModeChanged );
48  setLayer( layer );
49 
50  const int iconSize16 = QgsGuiUtils::scaleIconSize( 16 );
51  mEngineSettingsButton->setIconSize( QSize( iconSize16, iconSize16 ) );
52 }
53 
55 {
56  return qobject_cast<QgsLabelingGui *>( mWidget );
57 }
58 
60 {
61  if ( mOldSettings )
62  {
63  mLayer->setLabeling( mOldSettings.release() );
64  mLayer->setLabelsEnabled( mOldLabelsEnabled );
65  }
66  setLayer( mLayer );
67 }
68 
69 
71 {
72  if ( !mapLayer || mapLayer->type() != QgsMapLayerType::VectorLayer )
73  {
74  setEnabled( false );
75  return;
76  }
77  else
78  {
79  setEnabled( true );
80  }
81 
82  QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mapLayer );
83  mLayer = layer;
84  if ( mLayer->labeling() )
85  {
86  mOldSettings.reset( mLayer->labeling()->clone() );
87  }
88  else
89  mOldSettings.reset();
90  mOldLabelsEnabled = mLayer->labelsEnabled();
91 
92  adaptToLayer();
93 }
94 
96 {
97  if ( !mLayer )
98  return;
99 
100  whileBlocking( mLabelModeComboBox )->setCurrentIndex( -1 );
101 
102  // pick the right mode of the layer
103  if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == QLatin1String( "rule-based" ) )
104  {
105  mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeRuleBased ) );
106  }
107  else if ( mLayer->labelsEnabled() && mLayer->labeling()->type() == QLatin1String( "simple" ) )
108  {
109  const QgsPalLayerSettings lyr = mLayer->labeling()->settings();
110 
111  mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( lyr.drawLabels ? ModeSingle : ModeBlocking ) );
112  }
113  else
114  {
115  mLabelModeComboBox->setCurrentIndex( mLabelModeComboBox->findData( ModeNone ) );
116  }
117 
118  if ( QgsLabelingGui *lg = qobject_cast<QgsLabelingGui *>( mWidget ) )
119  {
120  lg->updateUi();
121  }
122 }
123 
125 {
126  const Mode mode = static_cast< Mode >( mLabelModeComboBox->currentData().toInt() );
127  switch ( mode )
128  {
129  case ModeRuleBased:
130  {
131  const QgsRuleBasedLabeling::Rule *rootRule = qobject_cast<QgsRuleBasedLabelingWidget *>( mWidget )->rootRule();
132 
133  mLayer->setLabeling( new QgsRuleBasedLabeling( rootRule->clone() ) );
134  mLayer->setLabelsEnabled( true );
135  break;
136  }
137 
138  case ModeSingle:
139  {
140  mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( qobject_cast<QgsLabelingGui *>( mWidget )->layerSettings() ) );
141  mLayer->setLabelsEnabled( true );
142  break;
143  }
144 
145  case ModeBlocking:
146  {
147  mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( *mSimpleSettings ) );
148  mLayer->setLabelsEnabled( true );
149  break;
150  }
151 
152  case ModeNone:
153  {
154  mLayer->setLabelsEnabled( false );
155  break;
156  }
157  }
158 }
159 
161 {
164  // trigger refresh
165  mLayer->triggerRepaint();
166 }
167 
168 void QgsLabelingWidget::labelModeChanged( int index )
169 {
170  if ( mWidget )
171  mStackedWidget->removeWidget( mWidget );
172 
173  delete mWidget;
174  mWidget = nullptr;
175 
176  if ( index < 0 )
177  return;
178 
179  const Mode mode = static_cast< Mode >( mLabelModeComboBox->currentData().toInt() );
180 
181  switch ( mode )
182  {
183  case ModeRuleBased:
184  {
185  // note - QgsRuleBasedLabelingWidget handles conversion of existing non-rule based labels to rule based
186  QgsRuleBasedLabelingWidget *ruleWidget = new QgsRuleBasedLabelingWidget( mLayer, mCanvas, this );
187  ruleWidget->setDockMode( dockMode() );
188  connect( ruleWidget, &QgsPanelWidget::showPanel, this, &QgsPanelWidget::openPanel );
190  mWidget = ruleWidget;
191  mStackedWidget->addWidget( mWidget );
192  mStackedWidget->setCurrentWidget( mWidget );
193  break;
194  }
195 
196  case ModeSingle:
197  case ModeBlocking:
198  {
199  mSimpleSettings.reset();
200  if ( mLayer->labeling() && mLayer->labeling()->type() == QLatin1String( "simple" ) )
201  {
202  mSimpleSettings.reset( new QgsPalLayerSettings( mLayer->labeling()->settings() ) );
203  }
204  else if ( mLayer->labeling() && mLayer->labeling()->type() == QLatin1String( "rule-based" ) )
205  {
206  // changing from rule-based to simple labels... grab first rule, and copy settings
207  const QgsRuleBasedLabeling *rl = static_cast<const QgsRuleBasedLabeling *>( mLayer->labeling() );
208  if ( const QgsRuleBasedLabeling::Rule *rootRule = rl->rootRule() )
209  {
210  if ( const QgsRuleBasedLabeling::Rule *firstChild = rootRule->children().value( 0 ) )
211  {
212  if ( firstChild->settings() )
213  mSimpleSettings.reset( new QgsPalLayerSettings( *firstChild->settings() ) );
214  }
215  }
216  }
217 
218  if ( !mSimpleSettings )
219  {
220  mSimpleSettings = std::make_unique< QgsPalLayerSettings >( QgsAbstractVectorLayerLabeling::defaultSettingsForLayer( mLayer ) );
221  }
222 
223  if ( mSimpleSettings->fieldName.isEmpty() )
224  mSimpleSettings->fieldName = mLayer->displayField();
225 
226  QgsSymbolWidgetContext context;
227  context.setMapCanvas( mMapCanvas );
228  context.setMessageBar( mMessageBar );
229 
230  switch ( mode )
231  {
232  case ModeSingle:
233  {
234  QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
235  simpleWidget->setContext( context );
236 
237  simpleWidget->setDockMode( dockMode() );
239  connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
240 
241  simpleWidget->setLabelMode( QgsLabelingGui::Labels );
242 
243  mWidget = simpleWidget;
244  break;
245  }
246  case ModeBlocking:
247  {
248  QgsLabelObstacleSettingsWidget *obstacleWidget = new QgsLabelObstacleSettingsWidget( this, mLayer );
249  obstacleWidget->setContext( context );
250  obstacleWidget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
251  obstacleWidget->setDockMode( dockMode() );
252  obstacleWidget->setSettings( mSimpleSettings->obstacleSettings() );
253  obstacleWidget->setDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
254 
255  mSimpleSettings->obstacleSettings().setIsObstacle( true );
256  mSimpleSettings->drawLabels = false;
257 
258  connect( obstacleWidget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
259  {
260  mSimpleSettings->setObstacleSettings( obstacleWidget->settings() );
261  obstacleWidget->updateDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
262  emit widgetChanged();
263  } );
265 
266  mWidget = obstacleWidget;
267  break;
268  }
269 
270  case ModeRuleBased:
271  case ModeNone:
272  break;
273  }
274 
275  mStackedWidget->addWidget( mWidget );
276  mStackedWidget->setCurrentWidget( mWidget );
277  break;
278  }
279 
280  case ModeNone:
281  break;
282  }
283  emit widgetChanged();
284 }
285 
286 void QgsLabelingWidget::showEngineConfigDialog()
287 {
289  if ( panel && panel->dockMode() )
290  {
293  panel->openPanel( widget );
294  }
295  else
296  {
297  QgsLabelEngineConfigDialog dialog( mCanvas, this );
298  dialog.exec();
299  // reactivate button's window
300  activateWindow();
301  }
302 }
virtual QgsAbstractVectorLayerLabeling * clone() const =0
Returns a new copy of the object.
virtual QgsPalLayerSettings settings(const QString &providerId=QString()) const =0
Gets associated label settings.
static QgsPalLayerSettings defaultSettingsForLayer(const QgsVectorLayer *layer)
Returns the default layer settings to use for the specified vector layer.
virtual QString type() const =0
Unique type string of the labeling configuration implementation.
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.
A widget for customising label obstacle settings.
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 setGeometryType(QgsWkbTypes::GeometryType type) override
Sets the geometry type of the features to customize the widget accordingly.
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.
void adaptToLayer()
reload the settings shown in the dialog from the current layer
QgsLabelingGui * labelingGui()
Returns the labeling gui widget or nullptr if none.
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.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
A panel widget that can be shown in the map style dock.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QgsMapLayerType type
Definition: qgsmaplayer.h:80
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
Contains settings for how a map layer will be labeled.
bool drawLabels
Whether to draw labels for this layer.
Base class for any widget that can be shown as a inline panel.
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 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.
bool dockMode()
Returns the dock mode state.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:468
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:519
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.
const QgsRuleBasedLabeling::RuleList & children() const
Returns all children rules of this rule.
QgsRuleBasedLabeling::Rule * clone() const
clone this rule, return new instance
Rule based labeling for a vector layer.
QgsRuleBasedLabeling::Rule * rootRule()
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.
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 data sets.
void setLabeling(QgsAbstractVectorLayerLabeling *labeling)
Sets labeling configuration.
bool labelsEnabled() const
Returns whether the layer contains labels which are enabled and should be drawn.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
void setLabelsEnabled(bool enabled)
Sets whether labels should be enabled for the layer.
const QgsAbstractVectorLayerLabeling * labeling() const
Access to const labeling configuration.
QString displayField() const
This is a shorthand for accessing the displayExpression if it is a simple field.
@ VectorLayer
Vector layer.
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:1443