QGIS API Documentation  3.10.0-A Coruña (6c816b4204)
qgscalloutwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscalloutwidget.cpp
3  ---------------------
4  begin : July 2019
5  copyright : (C) 2019 by Nyall Dawson
6  email : nyall dot dawson 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 "qgscalloutwidget.h"
17 #include "qgsvectorlayer.h"
19 #include "qgsunitselectionwidget.h"
20 #include "qgscallout.h"
23 #include "qgsauxiliarystorage.h"
24 
26 {
27  if ( mContext.expressionContext() )
28  return *mContext.expressionContext();
29 
32  symbolScope->addVariable( QgsExpressionContextScope::StaticVariable( QgsExpressionContext::EXPR_SYMBOL_COLOR, QColor(), true ) );
33  expContext << symbolScope;
34 
35  // additional scopes
36  const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
37  for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
38  {
39  expContext.appendScope( new QgsExpressionContextScope( scope ) );
40  }
41 
42  //TODO - show actual value
43  expContext.setOriginalValueVariable( QVariant() );
44 
45  expContext.setHighlightedVariables( QStringList() << QgsExpressionContext::EXPR_ORIGINAL_VALUE << QgsExpressionContext::EXPR_SYMBOL_COLOR );
46 
47  return expContext;
48 }
49 
51 {
52  mContext = context;
53  const auto unitSelectionWidgets = findChildren<QgsUnitSelectionWidget *>();
54  for ( QgsUnitSelectionWidget *unitWidget : unitSelectionWidgets )
55  {
56  unitWidget->setMapCanvas( mContext.mapCanvas() );
57  }
58  const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
59  for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
60  {
61  symbolWidget->setMapCanvas( mContext.mapCanvas() );
62  symbolWidget->setMessageBar( mContext.messageBar() );
63  }
64 }
65 
67 {
68  return mContext;
69 }
70 
72 {
73  button->init( key, callout()->dataDefinedProperties(), QgsCallout::propertyDefinitions(), mVectorLayer, true );
74  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsCalloutWidget::updateDataDefinedProperty );
75  connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsCalloutWidget::createAuxiliaryField );
76 
77  button->registerExpressionContextGenerator( this );
78 }
79 
80 void QgsCalloutWidget::createAuxiliaryField()
81 {
82  // try to create an auxiliary layer if not yet created
83  if ( !mVectorLayer->auxiliaryLayer() )
84  {
85  QgsNewAuxiliaryLayerDialog dlg( mVectorLayer, this );
86  dlg.exec();
87  }
88 
89  // return if still not exists
90  if ( !mVectorLayer->auxiliaryLayer() )
91  return;
92 
93  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
94  QgsCallout::Property key = static_cast< QgsCallout::Property >( button->propertyKey() );
96 
97  // create property in auxiliary storage if necessary
98  if ( !mVectorLayer->auxiliaryLayer()->exists( def ) )
99  {
100  QgsNewAuxiliaryFieldDialog dlg( def, mVectorLayer, true, this );
101  if ( dlg.exec() == QDialog::Accepted )
102  def = dlg.propertyDefinition();
103  }
104 
105  // return if still not exist
106  if ( !mVectorLayer->auxiliaryLayer()->exists( def ) )
107  return;
108 
109  // update property with join field name from auxiliary storage
110  QgsProperty property = button->toProperty();
111  property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
112  property.setActive( true );
113  button->updateFieldLists();
114  button->setToProperty( property );
115 
116  callout()->dataDefinedProperties().setProperty( key, button->toProperty() );
117 
118  emit changed();
119 }
120 
121 void QgsCalloutWidget::updateDataDefinedProperty()
122 {
123  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
124  QgsCallout::Property key = static_cast< QgsCallout::Property >( button->propertyKey() );
125  callout()->dataDefinedProperties().setProperty( key, button->toProperty() );
126  emit changed();
127 }
128 
130 
131 //
132 // QgsSimpleLineCalloutWidget
133 //
134 
135 QgsSimpleLineCalloutWidget::QgsSimpleLineCalloutWidget( QgsVectorLayer *vl, QWidget *parent )
136  : QgsCalloutWidget( parent, vl )
137 {
138  setupUi( this );
139 
140  // Callout options - to move to custom widgets when multiple callout styles exist
141  mCalloutLineStyleButton->setSymbolType( QgsSymbol::Line );
142  mCalloutLineStyleButton->setDialogTitle( tr( "Callout Symbol" ) );
143  mCalloutLineStyleButton->registerExpressionContextGenerator( this );
144 
145  mCalloutLineStyleButton->setLayer( vl );
152 
153  connect( mMinCalloutWidthUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::minimumLengthUnitWidgetChanged );
154  connect( mMinCalloutLengthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::minimumLengthChanged );
155 
156  connect( mOffsetFromAnchorUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::offsetFromAnchorUnitWidgetChanged );
157  connect( mOffsetFromAnchorSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::offsetFromAnchorChanged );
158  connect( mOffsetFromLabelUnitWidget, &QgsUnitSelectionWidget::changed, this, &QgsSimpleLineCalloutWidget::offsetFromLabelUnitWidgetChanged );
159  connect( mOffsetFromLabelSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsSimpleLineCalloutWidget::offsetFromLabelChanged );
160 
161  connect( mDrawToAllPartsCheck, &QCheckBox::toggled, this, &QgsSimpleLineCalloutWidget::drawToAllPartsToggled );
162 
163  // Anchor point options
164  mAnchorPointComboBox->addItem( tr( "Pole of Inaccessibility" ), static_cast< int >( QgsCallout::PoleOfInaccessibility ) );
165  mAnchorPointComboBox->addItem( tr( "Point on Exterior" ), static_cast< int >( QgsCallout::PointOnExterior ) );
166  mAnchorPointComboBox->addItem( tr( "Point on Surface" ), static_cast< int >( QgsCallout::PointOnSurface ) );
167  mAnchorPointComboBox->addItem( tr( "Centroid" ), static_cast< int >( QgsCallout::Centroid ) );
168  connect( mAnchorPointComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsSimpleLineCalloutWidget::mAnchorPointComboBox_currentIndexChanged );
169 
170  connect( mCalloutLineStyleButton, &QgsSymbolButton::changed, this, &QgsSimpleLineCalloutWidget::lineSymbolChanged );
171 }
172 
173 void QgsSimpleLineCalloutWidget::setCallout( QgsCallout *callout )
174 {
175  if ( !callout )
176  return;
177 
178  mCallout.reset( dynamic_cast<QgsSimpleLineCallout *>( callout->clone() ) );
179  if ( !mCallout )
180  return;
181 
182  mMinCalloutWidthUnitWidget->blockSignals( true );
183  mMinCalloutWidthUnitWidget->setUnit( mCallout->minimumLengthUnit() );
184  mMinCalloutWidthUnitWidget->setMapUnitScale( mCallout->minimumLengthMapUnitScale() );
185  mMinCalloutWidthUnitWidget->blockSignals( false );
186 
187  whileBlocking( mMinCalloutLengthSpin )->setValue( mCallout->minimumLength() );
188 
189  mOffsetFromAnchorUnitWidget->blockSignals( true );
190  mOffsetFromAnchorUnitWidget->setUnit( mCallout->offsetFromAnchorUnit() );
191  mOffsetFromAnchorUnitWidget->setMapUnitScale( mCallout->offsetFromAnchorMapUnitScale() );
192  mOffsetFromAnchorUnitWidget->blockSignals( false );
193  mOffsetFromLabelUnitWidget->blockSignals( true );
194  mOffsetFromLabelUnitWidget->setUnit( mCallout->offsetFromLabelUnit() );
195  mOffsetFromLabelUnitWidget->setMapUnitScale( mCallout->offsetFromLabelMapUnitScale() );
196  mOffsetFromLabelUnitWidget->blockSignals( false );
197  whileBlocking( mOffsetFromAnchorSpin )->setValue( mCallout->offsetFromAnchor() );
198  whileBlocking( mOffsetFromLabelSpin )->setValue( mCallout->offsetFromLabel() );
199 
200  whileBlocking( mCalloutLineStyleButton )->setSymbol( mCallout->lineSymbol()->clone() );
201 
202  whileBlocking( mDrawToAllPartsCheck )->setChecked( mCallout->drawCalloutToAllParts() );
203 
204  whileBlocking( mAnchorPointComboBox )->setCurrentIndex( mAnchorPointComboBox->findData( static_cast< int >( callout->anchorPoint() ) ) );
205 
207  registerDataDefinedButton( mOffsetFromAnchorDDBtn, QgsCallout::OffsetFromAnchor );
208  registerDataDefinedButton( mOffsetFromLabelDDBtn, QgsCallout::OffsetFromLabel );
211 }
212 
213 void QgsSimpleLineCalloutWidget::setGeometryType( QgsWkbTypes::GeometryType type )
214 {
215  bool isPolygon = type == QgsWkbTypes::PolygonGeometry;
216  mAnchorPointLbl->setEnabled( isPolygon );
217  mAnchorPointLbl->setVisible( isPolygon );
218  mAnchorPointComboBox->setEnabled( isPolygon );
219  mAnchorPointComboBox->setVisible( isPolygon );
220  mAnchorPointDDBtn->setEnabled( isPolygon );
221  mAnchorPointDDBtn->setVisible( isPolygon );
222 }
223 
224 QgsCallout *QgsSimpleLineCalloutWidget::callout()
225 {
226  return mCallout.get();
227 }
228 
229 void QgsSimpleLineCalloutWidget::minimumLengthChanged()
230 {
231  mCallout->setMinimumLength( mMinCalloutLengthSpin->value() );
232  emit changed();
233 }
234 
235 void QgsSimpleLineCalloutWidget::minimumLengthUnitWidgetChanged()
236 {
237  mCallout->setMinimumLengthUnit( mMinCalloutWidthUnitWidget->unit() );
238  mCallout->setMinimumLengthMapUnitScale( mMinCalloutWidthUnitWidget->getMapUnitScale() );
239  emit changed();
240 }
241 
242 void QgsSimpleLineCalloutWidget::offsetFromAnchorUnitWidgetChanged()
243 {
244  mCallout->setOffsetFromAnchorUnit( mOffsetFromAnchorUnitWidget->unit() );
245  mCallout->setOffsetFromAnchorMapUnitScale( mOffsetFromAnchorUnitWidget->getMapUnitScale() );
246  emit changed();
247 }
248 
249 void QgsSimpleLineCalloutWidget::offsetFromAnchorChanged()
250 {
251  mCallout->setOffsetFromAnchor( mOffsetFromAnchorSpin->value() );
252  emit changed();
253 }
254 
255 void QgsSimpleLineCalloutWidget::offsetFromLabelUnitWidgetChanged()
256 {
257  mCallout->setOffsetFromLabelUnit( mOffsetFromLabelUnitWidget->unit() );
258  mCallout->setOffsetFromLabelMapUnitScale( mOffsetFromLabelUnitWidget->getMapUnitScale() );
259  emit changed();
260 }
261 
262 void QgsSimpleLineCalloutWidget::offsetFromLabelChanged()
263 {
264  mCallout->setOffsetFromLabel( mOffsetFromLabelSpin->value() );
265  emit changed();
266 }
267 
268 void QgsSimpleLineCalloutWidget::lineSymbolChanged()
269 {
270  mCallout->setLineSymbol( mCalloutLineStyleButton->clonedSymbol< QgsLineSymbol >() );
271  emit changed();
272 }
273 
274 void QgsSimpleLineCalloutWidget::mAnchorPointComboBox_currentIndexChanged( int index )
275 {
276  mCallout->setAnchorPoint( static_cast<QgsCallout::AnchorPoint>( mAnchorPointComboBox->itemData( index ).toInt() ) );
277  emit changed();
278 }
279 
280 void QgsSimpleLineCalloutWidget::drawToAllPartsToggled( bool active )
281 {
282  mCallout->setDrawCalloutToAllParts( active );
283  emit changed();
284 }
285 
286 
287 //
288 // QgsManhattanLineCalloutWidget
289 //
290 
291 QgsManhattanLineCalloutWidget::QgsManhattanLineCalloutWidget( QgsVectorLayer *vl, QWidget *parent )
292  : QgsSimpleLineCalloutWidget( vl, parent )
293 {
294 
295 }
296 
297 
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
virtual QgsCallout * callout()=0
Returns the callout defined by the current settings in the widget.
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
Meters value as Map units.
Definition: qgsunittypes.h:154
Single variable definition for use within a QgsExpressionContextScope.
QList< QgsExpressionContextScope * > globalProjectAtlasMapLayerScopes(const QgsMapLayer *layer) const
Returns list of scopes: global, project, atlas, map, layer.
Abstract base class for callout renderers.
Definition: qgscallout.h:46
void registerDataDefinedButton(QgsPropertyOverrideButton *button, QgsCallout::Property key)
Registers a data defined override button.
Minimum length of callouts.
Definition: qgscallout.h:71
Distance to offset lines from anchor points.
Definition: qgscallout.h:72
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
Property
Data definable properties.
Definition: qgscallout.h:69
virtual QgsCallout * clone() const =0
Duplicates a callout by creating a deep copy of the callout.
void changed()
Emitted when the symbol&#39;s settings are changed.
The surface&#39;s centroid is used as anchor for polygon geometries.
Definition: qgscallout.h:91
A button for creating and modifying QgsSymbol settings.
Feature&#39;s anchor point position.
Definition: qgscallout.h:75
Line symbol.
Definition: qgssymbol.h:86
The surface&#39;s pole of inaccessibility used as anchor for polygon geometries.
Definition: qgscallout.h:88
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
QList< QgsUnitTypes::RenderUnit > RenderUnitList
List of render units.
Definition: qgsunittypes.h:218
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:1060
void createAuxiliaryField()
Emitted when creating a new auxiliary field.
QgsCalloutWidget(QWidget *parent, QgsVectorLayer *vl=nullptr)
Constructor for QgsCalloutWidget.
A dialog to create a new auxiliary layer.
void setField(const QString &field)
Sets the field name the property references.
A button for controlling property overrides which may apply to a widget.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
void changed()
Should be emitted whenever configuration changes happened on this symbol layer configuration.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
void setToProperty(const QgsProperty &property)
Sets the widget to reflect the current state of a QgsProperty.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
static QgsPropertiesDefinition propertyDefinitions()
Returns the definitions for data defined properties available for use in callouts.
Definition: qgscallout.cpp:141
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
Single scope for storing variables and functions for use within a QgsExpressionContext.
A store for object properties.
Definition: qgsproperty.h:229
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
Distance to offset lines from label area.
Definition: qgscallout.h:73
Definition for a property.
Definition: qgsproperty.h:46
A point on the surface&#39;s outline closest to the label is used as anchor for polygon geometries...
Definition: qgscallout.h:89
Whether callout lines should be drawn to all feature parts.
Definition: qgscallout.h:74
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:139
void changed()
Emitted when property definition changes.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the callout&#39;s property collection, used for data defined overrides.
Definition: qgscallout.h:240
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:227
Points (e.g., for font sizes)
Definition: qgsunittypes.h:151
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
int propertyKey() const
Returns the property key linked to the button.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
const QgsVectorLayer * vectorLayer() const
Returns the vector layer associated with the widget.
AnchorPoint anchorPoint() const
Returns the feature&#39;s anchor point position.
Definition: qgscallout.h:270
Represents a vector layer which manages a vector based data sets.
A point guaranteed to be on the surface is used as anchor for polygon geometries. ...
Definition: qgscallout.h:90
void updateFieldLists()
Updates list of fields.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout)...
QgsPropertyDefinition propertyDefinition() const
Returns the underlying property definition.
A dialog to create a new auxiliary field.
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...