[labeling] When a layer is set to "blocking" mode, expose the obstacle

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.
This commit is contained in:
Nyall Dawson 2019-12-04 12:06:11 +10:00
parent e70db922d0
commit 66456a30e7
11 changed files with 123 additions and 18 deletions

View File

@ -46,6 +46,9 @@ Returns the obstacle settings defined by the widget.
virtual void setGeometryType( QgsWkbTypes::GeometryType type );
virtual void updateDataDefinedProperties( QgsPropertyCollection &properties );
};
/************************************************************************

View File

@ -54,6 +54,8 @@ 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
@ -61,6 +63,16 @@ Returns the current data defined properties state as specified in the widget.
%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
@ -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:
@ -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

View File

@ -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

View File

@ -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 )
@ -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 );
@ -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 );
if ( index == 3 )
simpleWidget->setLabelMode( QgsLabelingGui::ObstaclesOnly );
else
simpleWidget->setLabelMode( static_cast< QgsLabelingGui::LabelMode >( index ) );
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() );
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;

View File

@ -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();
};

View File

@ -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 ) );
}

View File

@ -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;

View File

@ -107,6 +107,8 @@ void QgsLabelSettingsWidgetBase::createAuxiliaryField()
mDataDefinedProperties.setProperty( key, button->toProperty() );
emit auxiliaryFieldCreated();
emit changed();
}
@ -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 );

View File

@ -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;
@ -78,6 +79,15 @@ 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:
/**
@ -85,6 +95,11 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q
*/
void changed();
/**
* Emitted when an auxiliary field is created in the widget.
*/
void auxiliaryFieldCreated();
protected:
QgsExpressionContext createExpressionContext() const override;
@ -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();
@ -109,7 +129,6 @@ class GUI_EXPORT QgsLabelSettingsWidgetBase : public QgsPanelWidget, protected Q
QgsSymbolWidgetContext mContext;
QgsPropertyCollection mDataDefinedProperties;
};

View File

@ -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();

View File

@ -46,19 +46,29 @@ class TestQgsLabelSettingsWidget(unittest.TestCase):
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()