Skip to content
Permalink
Browse files

Add allowEvalError flag to QgsExpression widgets

Some expression functions insist on a complete context which we
sometimes are not able to provide. The user might still have enough
knowledge that the expression is valid and an error will still be shown.
  • Loading branch information
m-kuhn committed Dec 12, 2017
1 parent e9d4c06 commit 3abff0e938a8a976bd5865fba530abd63ed633ee
@@ -60,6 +60,33 @@ The builder widget that is used by the dialog
void setGeomCalculator( const QgsDistanceArea &da );
%Docstring
Sets geometry calculator used in distance/area calculations.
%End

bool allowEvalErrors() const;
%Docstring
Allow accepting invalid expressions. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
:rtype: bool
%End

void setAllowEvalErrors( bool allowEvalErrors );
%Docstring
Allow accepting expressions with evaluation errors. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
%End

signals:

void allowEvalErrorsChanged();
%Docstring
Allow accepting expressions with evaluation errors. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
%End

protected:
@@ -260,6 +260,24 @@ Sets the expression string for the widget
.. versionadded:: 3.0
%End

bool evalError() const;
%Docstring
Will be set to true if the current expression text reported an eval error
with the context.

.. versionadded:: 3.0
:rtype: bool
%End

bool parserError() const;
%Docstring
Will be set to true if the current expression text reports a parser error
with the context.

.. versionadded:: 3.0
:rtype: bool
%End

public slots:

void loadSampleValues();
@@ -294,6 +312,22 @@ Sets the expression string for the widget
\param isValid Is true if the expression the user has typed is valid.
%End

void evalErrorChanged();
%Docstring
Will be set to true if the current expression text reported an eval error
with the context.

.. versionadded:: 3.0
%End

void parserErrorChanged();
%Docstring
Will be set to true if the current expression text reported a parser error
with the context.

.. versionadded:: 3.0
%End

protected:
virtual void showEvent( QShowEvent *e );

@@ -123,6 +123,23 @@ set the geometry calculator used in the expression dialog
\param generator A QgsExpressionContextGenerator class that will be used to
create an expression context when required.
.. versionadded:: 3.0
%End

bool allowEvalErrors() const;
%Docstring
Allow accepting expressions with evaluation errors. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
:rtype: bool
%End

void setAllowEvalErrors( bool allowEvalErrors );
%Docstring
Allow accepting expressions with evaluation errors. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
%End

signals:
@@ -134,6 +151,14 @@ the signal is emitted when the currently selected field changes
void fieldChanged( const QString &fieldName, bool isValid );
%Docstring
fieldChanged signal with indication of the validity of the expression
%End

void allowEvalErrorsChanged();
%Docstring
Allow accepting expressions with evaluation errors. This can be useful when we are not able to
provide an expression context of which we are sure it's completely populated.

.. versionadded:: 3.0
%End

public slots:
@@ -3452,37 +3452,34 @@ static QVariant fcnRepresentValue( const QVariantList &values, const QgsExpressi
else if ( values.size() == 2 )
fieldName = QgsExpressionUtils::getStringValue( values.at( 1 ), parent );
}

QVariant value = values.at( 0 );

QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( "layer" ), parent );
const QgsFields fields = context->fields();
int fieldIndex = fields.lookupField( fieldName );

if ( layer )
if ( fieldIndex == -1 )
{
parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
}
else
{
const QgsFields fields = layer->fields();
int index = fields.lookupField( fieldName );
QgsVectorLayer *layer = QgsExpressionUtils::getVectorLayer( context->variable( "layer" ), parent );
const QgsEditorWidgetSetup setup = fields.at( fieldIndex ).editorWidgetSetup();
const QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );

const QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer ? layer->id() : QStringLiteral( "[None]" ), fieldName );

if ( index == -1 )
QVariant cache;
if ( !context->hasCachedValue( cacheKey ) )
{
parent->setEvalErrorString( QCoreApplication::translate( "expression", "%1: Field not found %2" ).arg( QStringLiteral( "represent_value" ), fieldName ) );
cache = formatter->createCache( layer, fieldIndex, setup.config() );
context->setCachedValue( cacheKey, cache );
}
else
{
QgsEditorWidgetSetup setup = layer->editorWidgetSetup( index );
QgsFieldFormatter *formatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
cache = context->cachedValue( cacheKey );

QString cacheKey = QStringLiteral( "repvalfcn:%1:%2" ).arg( layer->id(), fieldName );

QVariant cache;
if ( !context->hasCachedValue( cacheKey ) )
{
cache = formatter->createCache( layer, index, setup.config() );
context->setCachedValue( cacheKey, cache );
}
else
cache = context->cachedValue( cacheKey );

result = formatter->representValue( layer, index, setup.config(), cache, value );
}
result = formatter->representValue( layer, fieldIndex, setup.config(), cache, value );
}

return result;
@@ -25,16 +25,15 @@ QgsExpressionBuilderDialog::QgsExpressionBuilderDialog( QgsVectorLayer *layer, c
setupUi( this );
QgsGui::instance()->enableAutoGeometryRestore( this );

QPushButton *okButton = buttonBox->button( QDialogButtonBox::Ok );
connect( builder, &QgsExpressionBuilderWidget::expressionParsed, okButton, &QWidget::setEnabled );
connect( builder, &QgsExpressionBuilderWidget::parserErrorChanged, this, &QgsExpressionBuilderDialog::syncOkButtonEnabledState );
connect( builder, &QgsExpressionBuilderWidget::evalErrorChanged, this, &QgsExpressionBuilderDialog::syncOkButtonEnabledState );

builder->setExpressionContext( context );
builder->setLayer( layer );
builder->setExpressionText( startText );
builder->loadFieldNames();
builder->loadRecent( mRecentKey );


connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsExpressionBuilderDialog::showHelp );
}

@@ -80,7 +79,34 @@ void QgsExpressionBuilderDialog::setGeomCalculator( const QgsDistanceArea &da )
builder->setGeomCalculator( da );
}

bool QgsExpressionBuilderDialog::allowEvalErrors() const
{
return mAllowEvalErrors;
}

void QgsExpressionBuilderDialog::setAllowEvalErrors( bool allowEvalErrors )
{
if ( allowEvalErrors == mAllowEvalErrors )
return;

mAllowEvalErrors = allowEvalErrors;
syncOkButtonEnabledState();
emit allowEvalErrorsChanged();
}

void QgsExpressionBuilderDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector/expression.html" ) );
}

void QgsExpressionBuilderDialog::syncOkButtonEnabledState()
{
QPushButton *okButton = buttonBox->button( QDialogButtonBox::Ok );

if ( builder->parserError() )
okButton->setEnabled( false );
else if ( !builder->evalError() || mAllowEvalErrors )
okButton->setEnabled( true );
else
okButton->setEnabled( true );
}
@@ -31,6 +31,8 @@ class GUI_EXPORT QgsExpressionBuilderDialog : public QDialog, private Ui::QgsExp
{
Q_OBJECT

Q_PROPERTY( bool allowEvalErrors READ allowEvalErrors WRITE setAllowEvalErrors NOTIFY allowEvalErrorsChanged )

public:
QgsExpressionBuilderDialog( QgsVectorLayer *layer,
const QString &startText = QString(),
@@ -65,6 +67,32 @@ class GUI_EXPORT QgsExpressionBuilderDialog : public QDialog, private Ui::QgsExp
//! Sets geometry calculator used in distance/area calculations.
void setGeomCalculator( const QgsDistanceArea &da );

/**
* Allow accepting invalid expressions. This can be useful when we are not able to
* provide an expression context of which we are sure it's completely populated.
*
* \since QGIS 3.0
*/
bool allowEvalErrors() const;

/**
* Allow accepting expressions with evaluation errors. This can be useful when we are not able to
* provide an expression context of which we are sure it's completely populated.
*
* \since QGIS 3.0
*/
void setAllowEvalErrors( bool allowEvalErrors );

signals:

/**
* Allow accepting expressions with evaluation errors. This can be useful when we are not able to
* provide an expression context of which we are sure it's completely populated.
*
* \since QGIS 3.0
*/
void allowEvalErrorsChanged();

protected:

/**
@@ -79,9 +107,11 @@ class GUI_EXPORT QgsExpressionBuilderDialog : public QDialog, private Ui::QgsExp

private:
QString mRecentKey;
bool mAllowEvalErrors = false;

private slots:
void showHelp();
void syncOkButtonEnabledState();

};

@@ -578,6 +578,8 @@ void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
txtExpressionString->setToolTip( QLatin1String( "" ) );
lblPreview->setToolTip( QLatin1String( "" ) );
emit expressionParsed( false );
setParserError( true );
setEvalError( true );
return;
}

@@ -614,14 +616,18 @@ void QgsExpressionBuilderWidget::txtExpressionString_textChanged()
txtExpressionString->setToolTip( tooltip );
lblPreview->setToolTip( tooltip );
emit expressionParsed( false );
setParserError( exp.hasParserError() );
setEvalError( exp.hasEvalError() );
return;
}
else
{
lblPreview->setStyleSheet( QLatin1String( "" ) );
txtExpressionString->setToolTip( QLatin1String( "" ) );
lblPreview->setToolTip( QLatin1String( "" ) );
lblPreview->setStyleSheet( QString() );
txtExpressionString->setToolTip( QString() );
lblPreview->setToolTip( QString() );
emit expressionParsed( true );
setParserError( false );
setEvalError( false );
}
}

@@ -672,6 +678,34 @@ QString QgsExpressionBuilderWidget::formatLayerHelp( const QgsMapLayer *layer )
return text;
}

bool QgsExpressionBuilderWidget::parserError() const
{
return mParserError;
}

void QgsExpressionBuilderWidget::setParserError( bool parserError )
{
if ( parserError == mParserError )
return;

mParserError = parserError;
emit parserErrorChanged();
}

bool QgsExpressionBuilderWidget::evalError() const
{
return mEvalError;
}

void QgsExpressionBuilderWidget::setEvalError( bool evalError )
{
if ( evalError == mEvalError )
return;

mEvalError = evalError;
emit evalErrorChanged();
}

QStandardItemModel *QgsExpressionBuilderWidget::model()
{
return mModel;

0 comments on commit 3abff0e

Please sign in to comment.
You can’t perform that action at this time.