QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
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  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  mSimpleSettings.reset( new QgsPalLayerSettings() );
220 
221  if ( mSimpleSettings->fieldName.isEmpty() )
222  mSimpleSettings->fieldName = mLayer->displayField();
223 
224  QgsSymbolWidgetContext context;
225  context.setMapCanvas( mMapCanvas );
226  context.setMessageBar( mMessageBar );
227 
228  switch ( mode )
229  {
230  case ModeSingle:
231  {
232  QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
233  simpleWidget->setContext( context );
234 
235  simpleWidget->setDockMode( dockMode() );
237  connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
238 
239  simpleWidget->setLabelMode( QgsLabelingGui::Labels );
240 
241  mWidget = simpleWidget;
242  break;
243  }
244  case ModeBlocking:
245  {
246  QgsLabelObstacleSettingsWidget *obstacleWidget = new QgsLabelObstacleSettingsWidget( this, mLayer );
247  obstacleWidget->setContext( context );
248  obstacleWidget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
249  obstacleWidget->setDockMode( dockMode() );
250  obstacleWidget->setSettings( mSimpleSettings->obstacleSettings() );
251  obstacleWidget->setDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
252 
253  mSimpleSettings->obstacleSettings().setIsObstacle( true );
254  mSimpleSettings->drawLabels = false;
255 
256  connect( obstacleWidget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
257  {
258  mSimpleSettings->setObstacleSettings( obstacleWidget->settings() );
259  obstacleWidget->updateDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
260  emit widgetChanged();
261  } );
263 
264  mWidget = obstacleWidget;
265  break;
266  }
267 
268  case ModeRuleBased:
269  case ModeNone:
270  break;
271  }
272 
273  mStackedWidget->addWidget( mWidget );
274  mStackedWidget->setCurrentWidget( mWidget );
275  break;
276  }
277 
278  case ModeNone:
279  break;
280  }
281  emit widgetChanged();
282 }
283 
284 void QgsLabelingWidget::showEngineConfigDialog()
285 {
287  if ( panel && panel->dockMode() )
288  {
291  panel->openPanel( widget );
292  }
293  else
294  {
295  QgsLabelEngineConfigDialog dialog( mCanvas, this );
296  dialog.exec();
297  // reactivate button's window
298  activateWindow();
299  }
300 }
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.
virtual QString type() const =0
Unique type string of the labeling configuration implementation.
static QIcon getThemeIcon(const QString &name)
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:86
A panel widget that can be shown in the map style dock.
Base class for all map layer types.
Definition: qgsmaplayer.h:85
QgsMapLayerType type
Definition: qgsmaplayer.h:92
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:501
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:552
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.
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:263