Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 54 additions & 40 deletions app/attributes/fieldvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,26 @@
#include "featurelayerpair.h"
#include "mixedattributevalue.h"

#include "qgsfield.h"
#include "qgsvectorlayerutils.h"
#include <qgsfield.h>
#include <qgsvectorlayerutils.h>

#include <QRegularExpression>
#include <QLocale>

QString FieldValidator::numberInvalid() { return tr( "Value must be a number" ); };
QString FieldValidator::numberUpperBoundReached() { return tr( "Value must be lower than %1" ); };
QString FieldValidator::numberLowerBoundReached() { return tr( "Value must be higher than %1" ); };
QString FieldValidator::numberExceedingVariableLimits() { return tr( "Value is too large" );};
QString FieldValidator::numberMustBeInt() { return tr( "Field can not contain decimal places" );};
QString FieldValidator::textTooLong() { return tr( "Can not be longer than %1 characters" );};
QString FieldValidator::softNotNullFailed() { return tr( "Field should not be empty" );};
QString FieldValidator::hardNotNullFailed() { return tr( "Field must not be empty" );};
QString FieldValidator::softUniqueFailed() { return tr( "Value should be unique" );};
QString FieldValidator::hardUniqueFailed() { return tr( "Value must be unique" );};
QString FieldValidator::softExpressionFailed() { return tr( "Unmet QGIS expression constraint" );};
QString FieldValidator::hardExpressionFailed() { return tr( "Unmet QGIS expression constraint" );};
QString FieldValidator::genericValidationFailed() { return tr( "Not a valid value" );};

FieldValidator::FieldValidator( QObject *parent ) :
QObject( parent )
{
Expand All @@ -42,7 +56,7 @@ FieldValidator::ValidationStatus FieldValidator::validate( const FeatureLayerPai
if ( value.userType() == qMetaTypeId<MixedAttributeValue>() )
return Valid;

bool isNumeric = item.editorWidgetType() == QStringLiteral( "Range" ) || field.isNumeric();
const bool isNumeric = item.editorWidgetType() == QStringLiteral( "Range" ) || field.isNumeric();
if ( isNumeric )
{
state = validateNumericField( item, value, validationMessage );
Expand All @@ -62,7 +76,7 @@ FieldValidator::ValidationStatus FieldValidator::validate( const FeatureLayerPai
// Continue to check hard and soft QGIS constraints
QStringList errors;

bool hardConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( pair.layer(), pair.feature(), item.fieldIndex(), errors, QgsFieldConstraints::ConstraintStrengthHard );
const bool hardConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( pair.layer(), pair.feature(), item.fieldIndex(), errors, QgsFieldConstraints::ConstraintStrengthHard );
if ( !hardConstraintSatisfied )
{
validationMessage = constructConstraintValidationMessage( item, errors );
Expand All @@ -71,7 +85,7 @@ FieldValidator::ValidationStatus FieldValidator::validate( const FeatureLayerPai

errors.clear();

bool softConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( pair.layer(), pair.feature(), item.fieldIndex(), errors, QgsFieldConstraints::ConstraintStrengthSoft );
const bool softConstraintSatisfied = QgsVectorLayerUtils::validateAttribute( pair.layer(), pair.feature(), item.fieldIndex(), errors, QgsFieldConstraints::ConstraintStrengthSoft );
if ( !softConstraintSatisfied )
{
validationMessage = constructConstraintValidationMessage( item, errors );
Expand All @@ -88,18 +102,18 @@ FieldValidator::ValidationStatus FieldValidator::validateTextField( const FormIt
// Check if the text is not too long for the field
if ( field.length() > 0 )
{
const int vLength = value.toString().length();
const int vLength = static_cast<int>( value.toString().length() );

if ( vLength > field.length() )
{
validationMessage = ValidationTexts::textTooLong.arg( field.length() );
validationMessage = textTooLong().arg( field.length() );
return Error;
}
}

if ( !field.convertCompatible( value ) )
{
validationMessage = ValidationTexts::genericValidationFailed;
validationMessage = genericValidationFailed();
return Error;
}

Expand All @@ -117,7 +131,7 @@ FieldValidator::ValidationStatus FieldValidator::validateNumericField( const For

// in Qt 6 isNull() does not return true for true if the variant contained an object
// of a builtin type with an isNull() method that returned true for that object.
// So isNull() for QVariant( QString() ) will return false and we need to handle this
// So isNull() for QVariant( QString() ) will return false, and we need to handle this
// separately.
if ( value.userType() == QVariant::String && value.toString().isEmpty() )
{
Expand All @@ -126,17 +140,17 @@ FieldValidator::ValidationStatus FieldValidator::validateNumericField( const For

QString errorMessage;

bool containsDecimals = value.toString().contains( QLocale().decimalPoint() ) || value.toString().contains( "." );
const bool containsDecimals = value.toString().contains( QLocale().decimalPoint() ) || value.toString().contains( "." );

if ( !field.convertCompatible( value, &errorMessage ) )
{
if ( errorMessage.contains( QStringLiteral( "too large" ) ) )
{
validationMessage = ValidationTexts::numberExceedingVariableLimits;
validationMessage = numberExceedingVariableLimits();
}
else
{
validationMessage = ValidationTexts::numberInvalid;
validationMessage = numberInvalid();
}

return Error;
Expand All @@ -147,28 +161,28 @@ FieldValidator::ValidationStatus FieldValidator::validateNumericField( const For
* however, the value would not be saved and would get replaced by zero,
* so we need to handle it here and set invalid state for such input.
*/
validationMessage = ValidationTexts::numberMustBeInt;
validationMessage = numberMustBeInt();
return Error;
}

bool isRangeEditable = item.editorWidgetType() == QStringLiteral( "Range" ) &&
item.editorWidgetConfig().value( QStringLiteral( "Style" ) ) == QStringLiteral( "SpinBox" );
const bool isRangeEditable = item.editorWidgetType() == QStringLiteral( "Range" ) &&
item.editorWidgetConfig().value( QStringLiteral( "Style" ) ) == QStringLiteral( "SpinBox" );

// Check min/max range
if ( isRangeEditable )
{
double min = item.editorWidgetConfig().value( "Min" ).toDouble();
double max = item.editorWidgetConfig().value( "Max" ).toDouble();
double val = value.toDouble();
const double min = item.editorWidgetConfig().value( "Min" ).toDouble();
const double max = item.editorWidgetConfig().value( "Max" ).toDouble();
const double val = value.toDouble();

if ( val < min )
{
validationMessage = ValidationTexts::numberLowerBoundReached.arg( min );
validationMessage = numberLowerBoundReached().arg( min );
return Error;
}
else if ( val > max )
{
validationMessage = ValidationTexts::numberUpperBoundReached.arg( max );
validationMessage = numberUpperBoundReached().arg( max );
return Error;
}
}
Expand All @@ -182,7 +196,7 @@ FieldValidator::ValidationStatus FieldValidator::validateGenericField( const For

if ( !field.convertCompatible( value ) )
{
validationMessage = ValidationTexts::genericValidationFailed;
validationMessage = genericValidationFailed();
return Error;
}

Expand All @@ -197,50 +211,50 @@ QString FieldValidator::constructConstraintValidationMessage( const FormItem &it
*/

const QgsField field = item.field();
QgsFieldConstraints fldCons = field.constraints();
const QgsFieldConstraints &fldCons = field.constraints();
QStringList validationMessages;

bool hasNotNullConstraint = fldCons.constraints() & QgsFieldConstraints::ConstraintNotNull;
bool notNullViolated = unmetConstraints.contains( QStringLiteral( "value is NULL" ) );
const bool hasNotNullConstraint = fldCons.constraints() & QgsFieldConstraints::ConstraintNotNull;
const bool notNullViolated = unmetConstraints.contains( QStringLiteral( "value is NULL" ) );

if ( hasNotNullConstraint && notNullViolated )
{
QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintNotNull );
const QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintNotNull );

if ( strength == QgsFieldConstraints::ConstraintStrengthHard )
{
validationMessages << ValidationTexts::hardNotNullFailed;
validationMessages << hardNotNullFailed();
}
else if ( strength == QgsFieldConstraints::ConstraintStrengthSoft )
{
validationMessages << ValidationTexts::softNotNullFailed;
validationMessages << softNotNullFailed();
}
}

bool hasUniqueConstraint = fldCons.constraints() & QgsFieldConstraints::ConstraintUnique;
bool uniqueViolated = unmetConstraints.contains( QStringLiteral( "value is not unique" ) );
const bool hasUniqueConstraint = fldCons.constraints() & QgsFieldConstraints::ConstraintUnique;
const bool uniqueViolated = unmetConstraints.contains( QStringLiteral( "value is not unique" ) );

if ( hasUniqueConstraint && uniqueViolated )
{
QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintUnique );
const QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintUnique );

if ( strength == QgsFieldConstraints::ConstraintStrengthHard )
{
validationMessages << ValidationTexts::hardUniqueFailed;
validationMessages << hardUniqueFailed();
}
else if ( strength == QgsFieldConstraints::ConstraintStrengthSoft )
{
validationMessages << ValidationTexts::softUniqueFailed;
validationMessages << softUniqueFailed();
}
}

bool hasExpressionConstrain = fldCons.constraints() & QgsFieldConstraints::ConstraintExpression;
bool expressionViolated = unmetConstraints.filter( QRegularExpression( "(parser error|evaluation error|check failed)" ) ).size() > 0;
const bool hasExpressionConstrain = fldCons.constraints() & QgsFieldConstraints::ConstraintExpression;
const bool expressionViolated = !unmetConstraints.filter( QRegularExpression( "(parser error|evaluation error|check failed)" ) ).empty();

if ( hasExpressionConstrain && expressionViolated )
{
QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintExpression );
bool containsDescription = !fldCons.constraintDescription().isEmpty();
const QgsFieldConstraints::ConstraintStrength strength = fldCons.constraintStrength( QgsFieldConstraints::ConstraintExpression );
const bool containsDescription = !fldCons.constraintDescription().isEmpty();

if ( containsDescription )
{
Expand All @@ -250,19 +264,19 @@ QString FieldValidator::constructConstraintValidationMessage( const FormItem &it
{
if ( strength == QgsFieldConstraints::ConstraintStrengthHard )
{
validationMessages << ValidationTexts::hardExpressionFailed;
validationMessages << hardExpressionFailed();
}
else if ( strength == QgsFieldConstraints::ConstraintStrengthSoft )
{
validationMessages << ValidationTexts::softExpressionFailed;
validationMessages << softExpressionFailed();
}
}
}

if ( validationMessages.size() )
if ( !validationMessages.empty() )
{
return validationMessages.join( QStringLiteral( "\n" ) ); // each message on new line
}

return QString();
return {};
}
40 changes: 17 additions & 23 deletions app/attributes/fieldvalidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
#ifndef FIELDVALIDATOR_H
#define FIELDVALIDATOR_H

#include <QString>
#include <QVariant>
#include <QObject>

Expand Down Expand Up @@ -49,28 +48,23 @@ class FieldValidator : public QObject

private:
static QString constructConstraintValidationMessage( const FormItem &item, const QStringList &unmetConstraints );
};

namespace ValidationTexts
{

const QString numberInvalid = QObject::tr( "Value must be a number" );
const QString numberUpperBoundReached = QObject::tr( "Value must be lower than %1" );
const QString numberLowerBoundReached = QObject::tr( "Value must be higher than %1" );
const QString numberExceedingVariableLimits = QObject::tr( "Value is too large" );
const QString numberMustBeInt = QObject::tr( "Field can not contain decimal places" );

const QString textTooLong = QObject::tr( "Can not be longer than %1 characters" );

const QString softNotNullFailed = QObject::tr( "Field should not be empty" );
const QString hardNotNullFailed = QObject::tr( "Field must not be empty" );
const QString softUniqueFailed = QObject::tr( "Value should be unique" );
const QString hardUniqueFailed = QObject::tr( "Value must be unique" );
const QString softExpressionFailed = QObject::tr( "Unmet QGIS expression constraint" );
const QString hardExpressionFailed = QObject::tr( "Unmet QGIS expression constraint" );

const QString genericValidationFailed = QObject::tr( "Not a valid value" );

}
static QString numberInvalid();
static QString numberUpperBoundReached();
static QString numberLowerBoundReached();
static QString numberExceedingVariableLimits();
static QString numberMustBeInt();
static QString textTooLong();
static QString softNotNullFailed();
static QString hardNotNullFailed();
static QString softUniqueFailed();
static QString hardUniqueFailed();
static QString softExpressionFailed();
static QString hardExpressionFailed();
static QString genericValidationFailed();

friend class TestAttributeController;
friend class TestFormEditors;
};

#endif // FIELDVALIDATOR_H
34 changes: 15 additions & 19 deletions app/test/testattributecontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,49 +358,47 @@ void TestAttributeController::testValidationMessages()
FieldValidator::ValidationStatus expectedValidationStatus;
};

namespace V = ValidationTexts;

QList<testunit> testunits
{
// Attribute - Name Not NULL - SOFT
{ items.at( 1 ), QVariant(), V::softNotNullFailed, FieldValidator::Warning },
{ items.at( 1 ), QVariant(), FieldValidator::softNotNullFailed(), FieldValidator::Warning },
{ items.at( 1 ), QStringLiteral( "A" ), "", FieldValidator::Valid },
{ items.at( 1 ), QVariant( QString() ), V::softNotNullFailed, FieldValidator::Warning },
{ items.at( 1 ), QVariant( QString() ), FieldValidator::softNotNullFailed(), FieldValidator::Warning },
{ items.at( 1 ), "abcsd fsdkajf nsa ", "", FieldValidator::Valid },

// Attribute - Size Not NULL - HARD <0; 10000>
{ items.at( 2 ), QVariant(), V::hardNotNullFailed, FieldValidator::Error },
{ items.at( 2 ), QVariant(), FieldValidator::hardNotNullFailed(), FieldValidator::Error },
{ items.at( 2 ), "1", "", FieldValidator::Valid },
{ items.at( 2 ), "1a", V::numberInvalid, FieldValidator::Error },
{ items.at( 2 ), "10001", V::numberUpperBoundReached.arg( 10000 ), FieldValidator::Error },
{ items.at( 2 ), "-1", V::numberLowerBoundReached.arg( 0 ), FieldValidator::Error },
{ items.at( 2 ), "1a", FieldValidator::numberInvalid(), FieldValidator::Error },
{ items.at( 2 ), "10001", FieldValidator::numberUpperBoundReached().arg( 10000 ), FieldValidator::Error },
{ items.at( 2 ), "-1", FieldValidator::numberLowerBoundReached().arg( 0 ), FieldValidator::Error },
{ items.at( 2 ), "150", "", FieldValidator::Valid },

// Attribute - SectorId Unique - SOFT <-100; 1000>
{ items.at( 3 ), "1", "", FieldValidator::Valid },
{ items.at( 3 ), "-100", "", FieldValidator::Valid },
{ items.at( 3 ), "13", V::softUniqueFailed, FieldValidator::Warning }, // there should already be feature with such value
{ items.at( 3 ), "13", FieldValidator::softUniqueFailed(), FieldValidator::Warning }, // there should already be feature with such value
{ items.at( 3 ), "14", "", FieldValidator::Valid },
{ items.at( 3 ), "14sad", V::numberInvalid, FieldValidator::Error },
{ items.at( 3 ), "-", V::numberInvalid, FieldValidator::Error },
{ items.at( 3 ), ".", V::numberInvalid, FieldValidator::Error },
{ items.at( 3 ), "14sad", FieldValidator::numberInvalid(), FieldValidator::Error },
{ items.at( 3 ), "-", FieldValidator::numberInvalid(), FieldValidator::Error },
{ items.at( 3 ), ".", FieldValidator::numberInvalid(), FieldValidator::Error },
{ items.at( 3 ), "14", "", FieldValidator::Valid },

// Attribute - Occupied Expression, must be TRUE - HARD, expression descriptionn: 'Must be true'
{ items.at( 4 ), false, QStringLiteral( "Must be true" ), FieldValidator::Error },
{ items.at( 4 ), true, "", FieldValidator::Valid },

// Attribure - DateTime(datetime) Not NULL - HARD, format: yyyy-MM-dd HH:mm:ss (default)
{ items.at( 5 ), QVariant(), V::hardNotNullFailed, FieldValidator::Error },
{ items.at( 5 ), QVariant(), FieldValidator::hardNotNullFailed(), FieldValidator::Error },
{ items.at( 5 ), QVariant( QDateTime::fromString( "2020-03-10 10:40:30", "yyyy-MM-dd HH:mm:ss" ) ), "", FieldValidator::Valid },

// Attribure - LastEdit(date) Not NULL - HARD, format: dd-MM-yyyy (custom)
{ items.at( 6 ), QVariant(), V::hardNotNullFailed, FieldValidator::Error },
{ items.at( 6 ), QVariant(), FieldValidator::hardNotNullFailed(), FieldValidator::Error },
{ items.at( 6 ), QVariant( QDateTime::fromString( "29-10-1998", "dd-MM-yyyy" ) ), "", FieldValidator::Valid },

// Attribute - Hash Unique - HARD
{ items.at( 7 ), QVariant(), "", FieldValidator::Valid },
{ items.at( 7 ), "1", V::hardUniqueFailed, FieldValidator::Error },
{ items.at( 7 ), "1", FieldValidator::hardUniqueFailed(), FieldValidator::Error },
{ items.at( 7 ), QVariant(), "", FieldValidator::Valid },
{ items.at( 7 ), "2", "", FieldValidator::Valid },

Expand All @@ -409,7 +407,7 @@ void TestAttributeController::testValidationMessages()
{ items.at( 8 ), "f", "", FieldValidator::Valid },
{ items.at( 8 ), "fi", "", FieldValidator::Valid },
{ items.at( 8 ), "five ", "", FieldValidator::Valid },
{ items.at( 8 ), "five chars limit", V::textTooLong.arg( 5 ), FieldValidator::Error },
{ items.at( 8 ), "five chars limit", FieldValidator::textTooLong().arg( 5 ), FieldValidator::Error },
{ items.at( 8 ), "five ", "", FieldValidator::Valid }
};

Expand Down Expand Up @@ -609,13 +607,11 @@ void TestAttributeController::testRawValue()
FieldValidator::ValidationStatus expectedValidationStatus;
};

namespace V = ValidationTexts;

QList<testunit> testunits
{
{ items.at( 1 ), QVariant( 1 ), QVariant( "1" ), QVariant( "1" ), "", FieldValidator::Valid },
{ items.at( 1 ), QVariant( "1" ), QVariant( "1" ), QVariant( "1" ), "", FieldValidator::Valid },
{ items.at( 4 ), QVariant( "a" ), QVariant(), QVariant( "a" ), V::numberInvalid, FieldValidator::Error },
{ items.at( 4 ), QVariant( "a" ), QVariant(), QVariant( "a" ), FieldValidator::numberInvalid(), FieldValidator::Error },
{ items.at( 4 ), QVariant( "1" ), QVariant( 1 ), QVariant( "1" ), "", FieldValidator::Valid },
{ items.at( 4 ), QVariant( 1 ), QVariant( 1 ), QVariant( 1 ), "", FieldValidator::Valid },
};
Expand Down
Loading
Loading