Skip to content

Commit a761447

Browse files
committedMar 10, 2019
Report errors in labeling geometry generator expression
1 parent c452821 commit a761447

File tree

6 files changed

+114
-21
lines changed

6 files changed

+114
-21
lines changed
 

‎src/app/qgslabelinggui.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ QgsLabelingGui::QgsLabelingGui( QgsVectorLayer *layer, QgsMapCanvas *mapCanvas,
8282
connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
8383
connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::updateGeometryTypeBasedWidgets );
8484
connect( mGeometryGeneratorExpressionButton, &QToolButton::clicked, this, &QgsLabelingGui::showGeometryGeneratorExpressionBuilder );
85+
connect( mGeometryGeneratorGroupBox, &QGroupBox::toggled, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
86+
connect( mGeometryGenerator, &QgsCodeEditorExpression::textChanged, this, &QgsLabelingGui::validateGeometryGeneratorExpression );
87+
connect( mGeometryGeneratorType, qgis::overload<int>::of( &QComboBox::currentIndexChanged ), this, &QgsLabelingGui::validateGeometryGeneratorExpression );
8588

8689
mFieldExpressionWidget->registerExpressionContextGenerator( this );
8790

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

96+
mGeometryGeneratorWarningLabel->setStyleSheet( QStringLiteral( "color: #FFC107;" ) );
97+
9398
setLayer( layer );
9499
}
95100

96101
void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
97102
{
103+
mPreviewFeature = QgsFeature();
104+
98105
if ( !mapLayer || mapLayer->type() != QgsMapLayer::VectorLayer )
99106
{
100107
setEnabled( false );
@@ -216,7 +223,7 @@ void QgsLabelingGui::setLayer( QgsMapLayer *mapLayer )
216223
wrapCharacterEdit->setText( lyr.wrapChar );
217224
mAutoWrapLengthSpinBox->setValue( lyr.autoWrapLength );
218225
mAutoWrapTypeComboBox->setCurrentIndex( lyr.useMaxLineLengthForAutoWrap ? 0 : 1 );
219-
mFontMultiLineAlignComboBox->setCurrentIndex( ( unsigned int ) lyr.multilineAlign );
226+
mFontMultiLineAlignComboBox->setCurrentIndex( lyr.multilineAlign );
220227
chkPreserveRotation->setChecked( lyr.preserveRotation );
221228

222229
mPreviewBackgroundBtn->setColor( lyr.previewBkgrdColor );
@@ -698,9 +705,54 @@ void QgsLabelingGui::showGeometryGeneratorExpressionBuilder()
698705
expressionBuilder.setExpressionText( mGeometryGenerator->text() );
699706
expressionBuilder.setExpressionContext( createExpressionContext() );
700707

708+
QgsDistanceArea da;
709+
da.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
710+
da.setEllipsoid( QgsProject::instance()->ellipsoid() );
711+
expressionBuilder.setGeomCalculator( da );
712+
701713
if ( expressionBuilder.exec() )
702714
{
703715
mGeometryGenerator->setText( expressionBuilder.expressionText() );
704716
}
717+
}
718+
719+
void QgsLabelingGui::validateGeometryGeneratorExpression()
720+
{
721+
bool valid = true;
722+
723+
if ( mGeometryGeneratorGroupBox->isChecked() )
724+
{
725+
if ( !mPreviewFeature.isValid() && mLayer )
726+
mLayer->getFeatures( QgsFeatureRequest().setLimit( 1 ) ).nextFeature( mPreviewFeature );
727+
728+
QgsExpression expression( mGeometryGenerator->text() );
729+
QgsExpressionContext context = createExpressionContext();
730+
context.setFeature( mPreviewFeature );
731+
732+
expression.prepare( &context );
733+
734+
if ( expression.hasParserError() )
735+
{
736+
mGeometryGeneratorWarningLabel->setText( expression.parserErrorString() );
737+
valid = false;
738+
}
739+
else
740+
{
741+
const QVariant result = expression.evaluate( &context );
742+
const QgsGeometry geometry = result.value<QgsGeometry>();
743+
QgsWkbTypes::GeometryType configuredGeometryType = mGeometryGeneratorType->currentData().value<QgsWkbTypes::GeometryType>();
744+
if ( geometry.isNull() )
745+
{
746+
mGeometryGeneratorWarningLabel->setText( tr( "Result of the expression is not a geometry" ) );
747+
valid = false;
748+
}
749+
else if ( geometry.type() != configuredGeometryType )
750+
{
751+
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 ) ) );
752+
valid = false;
753+
}
754+
}
755+
}
705756

757+
mGeometryGeneratorWarningLabel->setVisible( !valid );
706758
}

‎src/app/qgslabelinggui.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,22 @@ class APP_EXPORT QgsLabelingGui : public QgsTextFormatWidget, private QgsExpress
6868
void syncDefinedCheckboxFrame( QgsPropertyOverrideButton *ddBtn, QCheckBox *chkBx, QFrame *f );
6969

7070
private slots:
71+
72+
/**
73+
* Called when the geometry type is changed and
74+
* configuration options which only work with a specific
75+
* geometry type should be updated.
76+
*/
7177
void updateGeometryTypeBasedWidgets();
7278
void showGeometryGeneratorExpressionBuilder();
79+
void validateGeometryGeneratorExpression();
7380

7481
private:
7582
QgsVectorLayer *mLayer = nullptr;
7683
const QgsPalLayerSettings &mSettings;
7784
QgsPropertyCollection mDataDefinedProperties;
7885
LabelMode mMode;
86+
QgsFeature mPreviewFeature;
7987

8088
QgsExpressionContext createExpressionContext() const override;
8189

‎src/core/qgspallabeling.cpp

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,25 @@
6161
#include "qgscurvepolygon.h"
6262
#include <QMessageBox>
6363

64+
// TODO: Move to qgis.h?
65+
66+
/**
67+
* Converts a string representation \a key of an enum into the value.
68+
* If it cannot be converted, the \a defaultValue will be returned.
69+
*
70+
*/
71+
template <class T>
72+
T enumValueToKey( const QString &key, T defaultValue )
73+
{
74+
const QMetaEnum metaEnum( QMetaEnum::fromType<T>() );
75+
bool ok;
76+
T result = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( key.toUtf8().constData(), &ok ) );
77+
if ( !ok )
78+
result = defaultValue;
79+
80+
return result;
81+
}
82+
6483

6584
using namespace pal;
6685

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

685-
geometryGenerator = layer->customProperty( QStringLiteral( "labeling/geometryGenerator" ), QString() ).toString();
686-
geometryGeneratorEnabled = layer->customProperty( QStringLiteral( "labeling/geometryGeneratorEnabled" ) ).toBool();
687-
688-
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
689-
geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( layer->customProperty( QStringLiteral( "labeling/geometryGeneratorType" ) ).toString().toUtf8().constData() ) );
690-
691704
mDataDefinedProperties.clear();
692705
if ( layer->customProperty( QStringLiteral( "labeling/ddProperties" ) ).isValid() )
693706
{
@@ -879,10 +892,15 @@ void QgsPalLayerSettings::readXml( QDomElement &elem, const QgsReadWriteContext
879892

880893
geometryGenerator = placementElem.attribute( QStringLiteral( "geometryGenerator" ) );
881894
geometryGeneratorEnabled = placementElem.attribute( QStringLiteral( "geometryGeneratorEnabled" ) ).toInt();
895+
geometryGeneratorType = enumValueToKey( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ), QgsWkbTypes::PointGeometry );
882896

897+
#if 0
883898
const QMetaEnum metaEnum( QMetaEnum::fromType<QgsWkbTypes::GeometryType>() );
884-
geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ).toUtf8().constData() ) );
885-
899+
bool ok;
900+
geometryGeneratorType = static_cast<QgsWkbTypes::GeometryType>( metaEnum.keyToValue( placementElem.attribute( QStringLiteral( "geometryGeneratorType" ) ).toUtf8().constData(), &ok ) );
901+
if ( !ok )
902+
geometryGeneratorType = QgsWkbTypes::GeometryType::PointGeometry;
903+
#endif
886904

887905
// rendering
888906
QDomElement renderingElem = elem.firstChildElement( QStringLiteral( "rendering" ) );

‎src/core/qgspallabeling.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ class CORE_EXPORT QgsPalLayerSettings
758758
QString geometryGenerator;
759759

760760
//! The type of the result geometry of the geometry generator.
761-
QgsWkbTypes::GeometryType geometryGeneratorType = QgsWkbTypes::GeometryType::UnknownGeometry;
761+
QgsWkbTypes::GeometryType geometryGeneratorType = QgsWkbTypes::GeometryType::PointGeometry;
762762

763763
//! Defines if the geometry generator is enabled or not. If disabled, the standard geometry will be taken.
764764
bool geometryGeneratorEnabled = false;

‎src/gui/qgstextformatwidget.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,7 +568,8 @@ void QgsTextFormatWidget::setWidgetMode( QgsTextFormatWidget::Mode mode )
568568

569569
void QgsTextFormatWidget::toggleDDButtons( bool visible )
570570
{
571-
Q_FOREACH ( QgsPropertyOverrideButton *button, findChildren< QgsPropertyOverrideButton * >() )
571+
const auto buttons = findChildren< QgsPropertyOverrideButton * >();
572+
for ( QgsPropertyOverrideButton *button : buttons )
572573
{
573574
button->setVisible( visible );
574575
}
@@ -650,6 +651,10 @@ void QgsTextFormatWidget::connectValueChanged( const QList<QWidget *> &widgets,
650651
{
651652
connect( w, SIGNAL( toggled( bool ) ), this, slot );
652653
}
654+
else if ( QgsCodeEditorExpression *w = qobject_cast<QgsCodeEditorExpression *>( widget ) )
655+
{
656+
connect( w, SIGNAL( textChanged() ), this, slot );
657+
}
653658
else
654659
{
655660
QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) );

‎src/ui/qgstextformatwidgetbase.ui

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3664,9 +3664,9 @@ font-style: italic;</string>
36643664
<property name="geometry">
36653665
<rect>
36663666
<x>0</x>
3667-
<y>-370</y>
3667+
<y>-400</y>
36683668
<width>772</width>
3669-
<height>1187</height>
3669+
<height>1211</height>
36703670
</rect>
36713671
</property>
36723672
<layout class="QVBoxLayout" name="verticalLayout_11">
@@ -5000,12 +5000,8 @@ font-style: italic;</string>
50005000
<bool>true</bool>
50015001
</property>
50025002
<layout class="QGridLayout" name="gridLayout_41">
5003-
<item row="1" column="1">
5004-
<widget class="QToolButton" name="mGeometryGeneratorExpressionButton">
5005-
<property name="text">
5006-
<string>...</string>
5007-
</property>
5008-
</widget>
5003+
<item row="1" column="0" rowspan="2">
5004+
<widget class="QgsCodeEditorExpression" name="mGeometryGenerator" native="true"/>
50095005
</item>
50105006
<item row="3" column="0" colspan="2">
50115007
<widget class="QComboBox" name="mGeometryGeneratorType">
@@ -5030,8 +5026,22 @@ font-style: italic;</string>
50305026
</property>
50315027
</spacer>
50325028
</item>
5033-
<item row="1" column="0" rowspan="2">
5034-
<widget class="QgsCodeEditorExpression" name="mGeometryGenerator" native="true"/>
5029+
<item row="1" column="1">
5030+
<widget class="QToolButton" name="mGeometryGeneratorExpressionButton">
5031+
<property name="text">
5032+
<string>...</string>
5033+
</property>
5034+
</widget>
5035+
</item>
5036+
<item row="4" column="0">
5037+
<widget class="QLabel" name="mGeometryGeneratorWarningLabel">
5038+
<property name="text">
5039+
<string/>
5040+
</property>
5041+
<property name="wordWrap">
5042+
<bool>true</bool>
5043+
</property>
5044+
</widget>
50355045
</item>
50365046
</layout>
50375047
</widget>

0 commit comments

Comments
 (0)
Please sign in to comment.