Skip to content

Commit

Permalink
[labeling] When a layer is set to "blocking" mode, expose the obstacle
Browse files Browse the repository at this point in the history
settings widget to allow users to tweak the obstacle behavior

Previously these settings were stuck inside the disabled label settings
widget, which meant that to edit them you had to temporarily enable simple
labels, tweak the setting, and then set back to obstacle mode... woot.
  • Loading branch information
nyalldawson committed Dec 4, 2019
1 parent e70db92 commit 66456a3
Show file tree
Hide file tree
Showing 11 changed files with 123 additions and 18 deletions.
Expand Up @@ -46,6 +46,9 @@ Returns the obstacle settings defined by the widget.
virtual void setGeometryType( QgsWkbTypes::GeometryType type );


virtual void updateDataDefinedProperties( QgsPropertyCollection &properties );


};

/************************************************************************
Expand Down
18 changes: 18 additions & 0 deletions python/gui/auto_generated/qgslabelsettingswidgetbase.sip.in
Expand Up @@ -54,13 +54,25 @@ Sets the geometry ``type`` of the features to customize the widget accordingly.
%Docstring
Returns the current data defined properties state as specified in the widget.

.. seealso:: :py:func:`updateDataDefinedProperties`

.. seealso:: :py:func:`setDataDefinedProperties`
%End

void setDataDefinedProperties( const QgsPropertyCollection &dataDefinedProperties );
%Docstring
Sets the current data defined properties to show in the widget.

.. seealso:: :py:func:`dataDefinedProperties`
%End

virtual void updateDataDefinedProperties( QgsPropertyCollection &properties );
%Docstring
Updates a data defined ``properties`` collection, correctly setting the values
for any properties related to this widget.

.. seealso:: :py:func:`setDataDefinedProperties`

.. seealso:: :py:func:`dataDefinedProperties`
%End

Expand All @@ -69,6 +81,11 @@ Sets the current data defined properties to show in the widget.
void changed();
%Docstring
Emitted when any of the settings described by the widget are changed.
%End

void auxiliaryFieldCreated();
%Docstring
Emitted when an auxiliary field is created in the widget.
%End

protected:
Expand All @@ -83,6 +100,7 @@ for the button and initializing the button to show the correct descriptions
and help text for the associated property.
%End


};

class QgsLabelSettingsWidgetDialog : QDialog
Expand Down
2 changes: 1 addition & 1 deletion python/gui/auto_generated/qgstextformatwidget.sip.in
Expand Up @@ -108,7 +108,7 @@ Emitted when the text format defined by the widget changes

void auxiliaryFieldCreated();
%Docstring
Emitted when an auxiliary field is creatd in the widget.
Emitted when an auxiliary field is created in the widget.

.. versionadded:: 3.10
%End
Expand Down
65 changes: 53 additions & 12 deletions src/app/qgslabelingwidget.cpp
Expand Up @@ -26,6 +26,7 @@
#include "qgsvectorlayerlabeling.h"
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgslabelobstaclesettingswidget.h"

QgsLabelingWidget::QgsLabelingWidget( QgsVectorLayer *layer, QgsMapCanvas *canvas, QWidget *parent, QgsMessageBar *messageBar )
: QgsMapLayerConfigWidget( layer, canvas, parent )
Expand Down Expand Up @@ -130,13 +131,21 @@ void QgsLabelingWidget::writeSettingsToLayer()
mLayer->setLabelsEnabled( true );
break;
}

case ModeSingle:
case ModeBlocking:
{
mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( qobject_cast<QgsLabelingGui *>( mWidget )->layerSettings() ) );
mLayer->setLabelsEnabled( true );
break;
}

case ModeBlocking:
{
mLayer->setLabeling( new QgsVectorLayerSimpleLabeling( *mSimpleSettings ) );
mLayer->setLabelsEnabled( true );
break;
}

case ModeNone:
{
mLayer->setLabelsEnabled( false );
Expand Down Expand Up @@ -209,23 +218,55 @@ void QgsLabelingWidget::labelModeChanged( int index )
if ( mSimpleSettings->fieldName.isEmpty() )
mSimpleSettings->fieldName = mLayer->displayField();

QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );

QgsSymbolWidgetContext context;
context.setMapCanvas( mMapCanvas );
context.setMessageBar( mMessageBar );
simpleWidget->setContext( context );

simpleWidget->setDockMode( dockMode() );
connect( simpleWidget, &QgsTextFormatWidget::widgetChanged, this, &QgsLabelingWidget::widgetChanged );
connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );
switch ( mode )
{
case ModeSingle:
{
QgsLabelingGui *simpleWidget = new QgsLabelingGui( mLayer, mCanvas, *mSimpleSettings, this );
simpleWidget->setContext( context );

simpleWidget->setDockMode( dockMode() );
connect( simpleWidget, &QgsTextFormatWidget::widgetChanged, this, &QgsLabelingWidget::widgetChanged );
connect( simpleWidget, &QgsLabelingGui::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );

simpleWidget->setLabelMode( QgsLabelingGui::Labels );

mWidget = simpleWidget;
break;
}
case ModeBlocking:
{
QgsLabelObstacleSettingsWidget *obstacleWidget = new QgsLabelObstacleSettingsWidget( this, mLayer );
obstacleWidget->setContext( context );
obstacleWidget->setGeometryType( mLayer ? mLayer->geometryType() : QgsWkbTypes::UnknownGeometry );
obstacleWidget->setDockMode( dockMode() );
obstacleWidget->setSettings( mSimpleSettings->obstacleSettings() );
obstacleWidget->setDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );

if ( index == 3 )
simpleWidget->setLabelMode( QgsLabelingGui::ObstaclesOnly );
else
simpleWidget->setLabelMode( static_cast< QgsLabelingGui::LabelMode >( index ) );
mSimpleSettings->obstacleSettings().setIsObstacle( true );
mSimpleSettings->drawLabels = false;

connect( obstacleWidget, &QgsLabelSettingsWidgetBase::changed, this, [ = ]
{
mSimpleSettings->setObstacleSettings( obstacleWidget->settings() );
obstacleWidget->updateDataDefinedProperties( mSimpleSettings->dataDefinedProperties() );
emit widgetChanged();
} );
connect( obstacleWidget, &QgsLabelSettingsWidgetBase::auxiliaryFieldCreated, this, &QgsLabelingWidget::auxiliaryFieldCreated );

mWidget = obstacleWidget;
break;
}

case ModeRuleBased:
case ModeNone:
break;
}

mWidget = simpleWidget;
mStackedWidget->addWidget( mWidget );
mStackedWidget->setCurrentWidget( mWidget );
break;
Expand Down
2 changes: 1 addition & 1 deletion src/gui/qgslabelinggui.cpp
Expand Up @@ -144,7 +144,7 @@ void QgsLabelingGui::showObstacleSettings()
{
mObstacleSettings = widget->settings();
const QgsPropertyCollection obstacleDataDefinedProperties = widget->dataDefinedProperties();
mDataDefinedProperties.setProperty( QgsPalLayerSettings::ObstacleFactor, obstacleDataDefinedProperties.property( QgsPalLayerSettings::ObstacleFactor ) );
widget->updateDataDefinedProperties( mDataDefinedProperties );
emit widgetChanged();
};

Expand Down
5 changes: 5 additions & 0 deletions src/gui/qgslabelobstaclesettingswidget.cpp
Expand Up @@ -63,3 +63,8 @@ void QgsLabelObstacleSettingsWidget::setGeometryType( QgsWkbTypes::GeometryType
mObstacleTypeComboBox->setVisible( type == QgsWkbTypes::PolygonGeometry || type == QgsWkbTypes::UnknownGeometry );
mObstacleTypeLabel->setVisible( type == QgsWkbTypes::PolygonGeometry || type == QgsWkbTypes::UnknownGeometry );
}

void QgsLabelObstacleSettingsWidget::updateDataDefinedProperties( QgsPropertyCollection &properties )
{
properties.setProperty( QgsPalLayerSettings::ObstacleFactor, mDataDefinedProperties.property( QgsPalLayerSettings::ObstacleFactor ) );
}
2 changes: 2 additions & 0 deletions src/gui/qgslabelobstaclesettingswidget.h
Expand Up @@ -57,6 +57,8 @@ class GUI_EXPORT QgsLabelObstacleSettingsWidget : public QgsLabelSettingsWidgetB

void setGeometryType( QgsWkbTypes::GeometryType type ) override;

void updateDataDefinedProperties( QgsPropertyCollection &properties ) override;

private:

bool mBlockSignals = false;
Expand Down
7 changes: 7 additions & 0 deletions src/gui/qgslabelsettingswidgetbase.cpp
Expand Up @@ -107,6 +107,8 @@ void QgsLabelSettingsWidgetBase::createAuxiliaryField()

mDataDefinedProperties.setProperty( key, button->toProperty() );

emit auxiliaryFieldCreated();

emit changed();
}

Expand Down Expand Up @@ -135,6 +137,11 @@ void QgsLabelSettingsWidgetBase::setDataDefinedProperties( const QgsPropertyColl
}
}

void QgsLabelSettingsWidgetBase::updateDataDefinedProperties( QgsPropertyCollection & )
{

}

void QgsLabelSettingsWidgetBase::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key )
{
button->init( key, mDataDefinedProperties, QgsPalLayerSettings::propertyDefinitions(), mVectorLayer, true );
Expand Down
21 changes: 20 additions & 1 deletion src/gui/qgslabelsettingswidgetbase.h
Expand Up @@ -67,6 +67,7 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q
/**
* Returns the current data defined properties state as specified in the widget.
*
* \see updateDataDefinedProperties()
* \see setDataDefinedProperties()
*/
QgsPropertyCollection dataDefinedProperties() const;
Expand All @@ -78,13 +79,27 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q
*/
void setDataDefinedProperties( const QgsPropertyCollection &dataDefinedProperties );

/**
* Updates a data defined \a properties collection, correctly setting the values
* for any properties related to this widget.
*
* \see setDataDefinedProperties()
* \see dataDefinedProperties()
*/
virtual void updateDataDefinedProperties( QgsPropertyCollection &properties );

signals:

/**
* Emitted when any of the settings described by the widget are changed.
*/
void changed();

/**
* Emitted when an auxiliary field is created in the widget.
*/
void auxiliaryFieldCreated();

protected:

QgsExpressionContext createExpressionContext() const override;
Expand All @@ -96,6 +111,11 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q
*/
void registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsPalLayerSettings::Property key );

/**
* Contains the data defined properties defined by the widget.
*/
QgsPropertyCollection mDataDefinedProperties;

private slots:

void createAuxiliaryField();
Expand All @@ -109,7 +129,6 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q

QgsSymbolWidgetContext mContext;

QgsPropertyCollection mDataDefinedProperties;

};

Expand Down
2 changes: 1 addition & 1 deletion src/gui/qgstextformatwidget.h
Expand Up @@ -118,7 +118,7 @@ class GUI_EXPORT QgsTextFormatWidget : public QWidget, public QgsExpressionConte
void widgetChanged();

/**
* Emitted when an auxiliary field is creatd in the widget.
* Emitted when an auxiliary field is created in the widget.
* \since QGIS 3.10
*/
void auxiliaryFieldCreated();
Expand Down
14 changes: 12 additions & 2 deletions tests/src/python/test_qgslabelsettingswidget.py
Expand Up @@ -46,19 +46,29 @@ def testObstacles(self):
settings.setFactor(0.4)
settings.setType(QgsLabelObstacleSettings.PolygonBoundary)
spy = QSignalSpy(w.changed)
w.setObstacleSettings(settings)
w.setSettings(settings)
self.assertEqual(len(spy), 0)
settings = w.settings()
self.assertEqual(settings.factor(), 0.4)
self.assertEqual(settings.type(), QgsLabelObstacleSettings.PolygonBoundary)
settings.setFactor(1.2)
settings.setType(QgsLabelObstacleSettings.PolygonInterior)
w.setObstacleSettings(settings)
w.setSettings(settings)
self.assertEqual(len(spy), 0)
settings = w.settings()
self.assertEqual(settings.factor(), 1.2)
self.assertEqual(settings.type(), QgsLabelObstacleSettings.PolygonInterior)

props = QgsPropertyCollection()
props.setProperty(QgsPalLayerSettings.ObstacleFactor, QgsProperty.fromValue(5))
w.setDataDefinedProperties(props)

props = QgsPropertyCollection()
self.assertFalse(props.isActive(QgsPalLayerSettings.ObstacleFactor))
w.updateDataDefinedProperties(props)
self.assertTrue(props.isActive(QgsPalLayerSettings.ObstacleFactor))
self.assertEqual(w.dataDefinedProperties().property(QgsPalLayerSettings.ObstacleFactor).asExpression(), '5')


if __name__ == '__main__':
unittest.main()

0 comments on commit 66456a3

Please sign in to comment.