Skip to content

Commit

Permalink
Report errors in labeling geometry generator expression
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed Mar 10, 2019
1 parent c452821 commit a761447
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 21 deletions.
54 changes: 53 additions & 1 deletion src/app/qgslabelinggui.cpp
Expand Up @@ -82,6 +82,9 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas,
connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets ); connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets ); connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder ); connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );


mFieldExpressionWidget->registerExpressionContextGenerator( this ); mFieldExpressionWidget->registerExpressionContextGenerator( this );


Expand All @@ -90,11 +93,15 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas,
mMaxScaleWidget->setMapCanvas( mapCanvas ); mMaxScaleWidget->setMapCanvas( mapCanvas );
mMaxScaleWidget->setShowCurrentScaleButton( true ); mMaxScaleWidget->setShowCurrentScaleButton( true );


mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) );

setLayer( layer ); setLayer( layer );
} }


void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer ) void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
{ {
mPreviewFeature = QgsFeature();

if ( !mapLayer || mapLayer->type() != QgsMapLayer::VectorLayer ) if ( !mapLayer || mapLayer->type() != QgsMapLayer::VectorLayer )
{ {
setEnabled( false ); setEnabled( false );
Expand Down Expand Up @@ -216,7 +223,7 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
wrapCharacterEdit->setText( lyr.wrapChar ); wrapCharacterEdit->setText( lyr.wrapChar );
mAutoWrapLengthSpinBox->setValue( lyr.autoWrapLength ); mAutoWrapLengthSpinBox->setValue( lyr.autoWrapLength );
mAutoWrapTypeComboBox->setCurrentIndex( lyr.useMaxLineLengthForAutoWrap ? 0 : 1 ); mAutoWrapTypeComboBox->setCurrentIndex( lyr.useMaxLineLengthForAutoWrap ? 0 : 1 );
mFontMultiLineAlignComboBox->setCurrentIndex( ( unsigned int ) lyr.multilineAlign ); mFontMultiLineAlignComboBox->setCurrentIndex( lyr.multilineAlign );
chkPreserveRotation->setChecked( lyr.preserveRotation ); chkPreserveRotation->setChecked( lyr.preserveRotation );


mPreviewBackgroundBtn->setColor( lyr.previewBkgrdColor ); mPreviewBackgroundBtn->setColor( lyr.previewBkgrdColor );
Expand Down Expand Up @@ -698,9 +705,54 @@ void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
expressionBuilder.setExpressionText( mGeometryGenerator->text() ); expressionBuilder.setExpressionText( mGeometryGenerator->text() );
expressionBuilder.setExpressionContext( createExpressionContext() ); expressionBuilder.setExpressionContext( createExpressionContext() );


QgsDistanceArea da;
da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
da.setEllipsoid( QgsProject::instance()->ellipsoid() );
expressionBuilder.setGeomCalculator( da );

if ( expressionBuilder.exec() ) if ( expressionBuilder.exec() )
{ {
mGeometryGenerator->setText( expressionBuilder.expressionText() ); mGeometryGenerator->setText( expressionBuilder.expressionText() );
} }
}

void QgsLabelingGui::validateGeometryGeneratorExpression()
{
bool valid = true;

if ( mGeometryGeneratorGroupBox->isChecked() )
{
if ( !mPreviewFeature.isValid() && mLayer )
mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );

QgsExpression expression( mGeometryGenerator->text() );
QgsExpressionContext context = createExpressionContext();
context.setFeature( mPreviewFeature );

expression.prepare( &context );

if ( expression.hasParserError() )
{
mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
valid = false;
}
else
{
const QVariant result = expression.evaluate( &context );
const QgsGeometry geometry = result.value<QgsGeometry>();
QgsWkbTypes::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
if ( geometry.isNull() )
{
mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
valid = false;
}
else if ( geometry.type() != configuredGeometryType )
{
mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression does not match configured geometry type. Result is %1, Configured %2." ).arg( QgsWkbTypes::geometryDisplayString( geometry.type() ), QgsWkbTypes::geometryDisplayString( configuredGeometryType ) ) );
valid = false;
}
}
}


mGeometryGeneratorWarningLabel->setVisible( !valid );
} }
8 changes: 8 additions & 0 deletions src/app/qgslabelinggui.h
Expand Up @@ -68,14 +68,22 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
void syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f ); void syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f );


private slots: private slots:

/**
* Called when the geometry type is changed and
* configuration options which only work with a specific
* geometry type should be updated.
*/
void updateGeometryTypeBasedWidgets(); void updateGeometryTypeBasedWidgets();
void showGeometryGeneratorExpressionBuilder(); void showGeometryGeneratorExpressionBuilder();
void validateGeometryGeneratorExpression();


private: private:
QgsVectorLayer *mLayer = nullptr; QgsVectorLayer *mLayer = nullptr;
const QgsPalLayerSettings &mSettings; const QgsPalLayerSettings &mSettings;
QgsPropertyCollection mDataDefinedProperties; QgsPropertyCollection mDataDefinedProperties;
LabelMode mMode; LabelMode mMode;
QgsFeature mPreviewFeature;


QgsExpressionContext createExpressionContext() const override; QgsExpressionContext createExpressionContext() const override;


Expand Down
34 changes: 26 additions & 8 deletions src/core/qgspallabeling.cpp
Expand Up @@ -61,6 +61,25 @@
#include "qgscurvepolygon.h" #include "qgscurvepolygon.h"
#include <QMessageBox> #include <QMessageBox>


// TODO: Move to qgis.h?

/**
* Converts a string representation \a key of an enum into the value.
* If it cannot be converted, the \a defaultValue will be returned.
*
*/
template <class T>
T enumValueToKey( const QString &key, T defaultValue )
{
const QMetaEnum metaEnum( QMetaEnum::fromType<T>() );
bool ok;
T result = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( key.toUtf8().constData(), &ok ) );
if ( !ok )
result = defaultValue;

return result;
}



using namespace pal; using namespace pal;


Expand Down Expand Up @@ -682,12 +701,6 @@ void QgsPalLayerSettings::readFromLayerCustomProperties( QgsVectorLayer *layer )
obstacleType = static_cast< ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() ); obstacleType = static_cast< ObstacleType >( layer->customProperty( QStringLiteral( "labeling/obstacleType" ), QVariant( PolygonInterior ) ).toUInt() );
zIndex = layer->customProperty( QStringLiteral( "labeling/zIndex" ), QVariant( 0.0 ) ).toDouble(); zIndex = layer->customProperty( QStringLiteral( "labeling/zIndex" ), QVariant( 0.0 ) ).toDouble();


geometryGenerator = layer->customProperty( QStringLiteral( "labeling/geometryGenerator" ), QString() ).toString();
geometryGeneratorEnabled = layer->customProperty( QStringLiteral( "labeling/geometryGeneratorEnabled" ) ).toBool();

const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( layer->customProperty( QStringLiteral( "labeling/geometryGeneratorType" ) ).toString().toUtf8().constData() ) );

mDataDefinedProperties.clear(); mDataDefinedProperties.clear();
if ( layer->customProperty( QStringLiteral( "labeling/ddProperties" ) ).isValid() ) if ( layer->customProperty( QStringLiteral( "labeling/ddProperties" ) ).isValid() )
{ {
Expand Down Expand Up @@ -879,10 +892,15 @@ void QgsPalLayerSettings::readXml( QDomElement &elem, const QgsReadWriteContext


geometryGenerator = placementElem.attribute( QStringLiteral( "geometryGenerator" ) ); geometryGenerator = placementElem.attribute( QStringLiteral( "geometryGenerator" ) );
geometryGeneratorEnabled = placementElem.attribute( QStringLiteral( "geometryGeneratorEnabled" ) ).toInt(); geometryGeneratorEnabled = placementElem.attribute( QStringLiteral( "geometryGeneratorEnabled" ) ).toInt();
geometryGeneratorType = enumValueToKey( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ), QgsWkbTypes::PointGeometry );


#if 0
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() ); const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ).toUtf8().constData() ) ); bool ok;

geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ).toUtf8().constData(), &ok ) );
if ( !ok )
geometryGeneratorType = QgsWkbTypes::GeometryType::PointGeometry;
#endif


// rendering // rendering
QDomElement renderingElem = elem.firstChildElement( QStringLiteral( "rendering" ) ); QDomElement renderingElem = elem.firstChildElement( QStringLiteral( "rendering" ) );
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgspallabeling.h
Expand Up @@ -758,7 +758,7 @@ class CORE_EXPORT QgsPalLayerSettings
QString geometryGenerator; QString geometryGenerator;


//! The type of the result geometry of the geometry generator. //! The type of the result geometry of the geometry generator.
QgsWkbTypes::GeometryType geometryGeneratorType = QgsWkbTypes::GeometryType::UnknownGeometry; QgsWkbTypes::GeometryType geometryGeneratorType = QgsWkbTypes::GeometryType::PointGeometry;


//! Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken. //! Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken.
bool geometryGeneratorEnabled = false; bool geometryGeneratorEnabled = false;
Expand Down
7 changes: 6 additions & 1 deletion src/gui/qgstextformatwidget.cpp
Expand Up @@ -568,7 +568,8 @@ void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )


void QgsTextFormatWidget::toggleDDButtons( bool visible ) void QgsTextFormatWidget::toggleDDButtons( bool visible )
{ {
Q_FOREACH ( QgsPropertyOverrideButton *button, findChildren< QgsPropertyOverrideButton * >() ) const auto buttons = findChildren< QgsPropertyOverrideButton * >();
for ( QgsPropertyOverrideButton *button : buttons )
{ {
button->setVisible( visible ); button->setVisible( visible );
} }
Expand Down Expand Up @@ -650,6 +651,10 @@ void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *> &widgets,
{ {
connect( w, SIGNAL( toggled( bool ) ), this, slot ); connect( w, SIGNAL( toggled( bool ) ), this, slot );
} }
else if ( QgsCodeEditorExpression *w = qobject_cast<QgsCodeEditorExpression *>( widget ) )
{
connect( w, SIGNAL( textChanged() ), this, slot );
}
else else
{ {
QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) ); QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) );
Expand Down
30 changes: 20 additions & 10 deletions src/ui/qgstextformatwidgetbase.ui
Expand Up @@ -3664,9 +3664,9 @@ font-style: italic;</string>
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-370</y> <y>-400</y>
<width>772</width> <width>772</width>
<height>1187</height> <height>1211</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_11"> <layout class="QVBoxLayout" name="verticalLayout_11">
Expand Down Expand Up @@ -5000,12 +5000,8 @@ font-style: italic;</string>
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout" name="gridLayout_41"> <layout class="QGridLayout" name="gridLayout_41">
<item row="1" column="1"> <item row="1" column="0" rowspan="2">
<widget class="QToolButton" name="mGeometryGeneratorExpressionButton"> <widget class="QgsCodeEditorExpression" name="mGeometryGenerator" native="true"/>
<property name="text">
<string>...</string>
</property>
</widget>
</item> </item>
<item row="3" column="0" colspan="2"> <item row="3" column="0" colspan="2">
<widget class="QComboBox" name="mGeometryGeneratorType"> <widget class="QComboBox" name="mGeometryGeneratorType">
Expand All @@ -5030,8 +5026,22 @@ font-style: italic;</string>
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="0" rowspan="2"> <item row="1" column="1">
<widget class="QgsCodeEditorExpression" name="mGeometryGenerator" native="true"/> <widget class="QToolButton" name="mGeometryGeneratorExpressionButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="mGeometryGeneratorWarningLabel">
<property name="text">
<string/>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item> </item>
</layout> </layout>
</widget> </widget>
Expand Down

0 comments on commit a761447

Please sign in to comment.