Skip to content

Commit

Permalink
Refactor constraint handling
Browse files Browse the repository at this point in the history
- store constraint origin in QgsField
- move handling of constraint expressions to QgsField
  • Loading branch information
nyalldawson committed Nov 2, 2016
1 parent 1cecf37 commit f99ea26
Show file tree
Hide file tree
Showing 19 changed files with 302 additions and 65 deletions.
60 changes: 58 additions & 2 deletions python/core/qgsfield.sip
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ class QgsField
};
typedef QFlags<QgsField::Constraint> Constraints;

/**
* Origin of constraints.
* @note added in QGIS 3.0
*/
enum ConstraintOrigin
{
ConstraintOriginNotSet, //!< Constraint is not set
ConstraintOriginProvider, //!< Constraint was set at data provider
ConstraintOriginLayer, //!< Constraint was set by layer
};

/** Constructor. Constructs a new QgsField object.
* @param name Field name
* @param type Field variant type, currently supported: String / Int / Double
Expand Down Expand Up @@ -178,15 +189,60 @@ class QgsField
* Returns any constraints which are present for the field.
* @note added in QGIS 3.0
* @see setConstraints()
* @see constraintOrigin()
*/
Constraints constraints() const;

/**
* Sets constraints which are present for the field.
* Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint
* is not present on this field.
* @note added in QGIS 3.0
* @see constraints()
*/
ConstraintOrigin constraintOrigin( Constraint constraint ) const;

/**
* Sets a constraint on the field.
* @note added in QGIS 3.0
* @see constraints()
* @see removeConstraint()
*/
void setConstraint( Constraint constraint, ConstraintOrigin origin = ConstraintOriginLayer );

/**
* Removes a constraint from the field.
* @see setConstraint()
* @see constraints()
*/
void removeConstraint( Constraint constraint );

/**
* Returns the constraint expression for the field, if set.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintDescription()
* @see setConstraintExpression()
*/
QString constraintExpression() const;

/**
* Returns the descriptive name for the constraint expression.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintExpression()
* @see setConstraintExpression()
*/
QString constraintDescription() const;

/**
* Set the constraint expression for the field. An optional descriptive name for the constraint
* can also be set. Setting an empty expression will clear any existing expression constraint.
* @note added in QGIS 3.0
* @see constraintExpression()
* @see constraintDescription()
* @see constraints()
*/
void setConstraints( Constraints constraints );
void setConstraintExpression( const QString& expression, const QString& description = QString() );

/** Returns the alias for the field (the friendly displayed name of the field ),
* or an empty string if there is no alias.
Expand Down
2 changes: 1 addition & 1 deletion python/core/qgsvectordataprovider.sip
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ class QgsVectorDataProvider : QgsDataProvider
* field index.
* @note added in QGIS 3.0
*/
virtual QgsField::Constraints fieldConstraints( int fieldIndex ) const;
QgsField::Constraints fieldConstraints( int fieldIndex ) const;

/**
* Changes geometries of existing features
Expand Down
12 changes: 7 additions & 5 deletions src/app/qgsfieldsproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,10 +562,12 @@ void QgsFieldsProperties::attributeTypeDialog()
attributeTypeDialog.setUnique( cfg.mConstraints & QgsField::ConstraintUnique );

QgsField::Constraints providerConstraints = 0;
if ( mLayer->fields().fieldOrigin( index ) == QgsFields::OriginProvider )
{
providerConstraints = mLayer->dataProvider()->fieldConstraints( mLayer->fields().fieldOriginIndex( index ) );
}
if ( mLayer->fields().at( index ).constraintOrigin( QgsField::ConstraintNotNull ) == QgsField::ConstraintOriginProvider )
providerConstraints |= QgsField::ConstraintNotNull;
if ( mLayer->fields().at( index ).constraintOrigin( QgsField::ConstraintUnique ) == QgsField::ConstraintOriginProvider )
providerConstraints |= QgsField::ConstraintUnique;
if ( mLayer->fields().at( index ).constraintOrigin( QgsField::ConstraintExpression ) == QgsField::ConstraintOriginProvider )
providerConstraints |= QgsField::ConstraintExpression;
attributeTypeDialog.setProviderConstraints( providerConstraints );

attributeTypeDialog.setConstraintExpression( cfg.mConstraint );
Expand Down Expand Up @@ -1059,7 +1061,7 @@ QgsFieldsProperties::FieldConfig::FieldConfig( QgsVectorLayer* layer, int idx )
mEditableEnabled = layer->fields().fieldOrigin( idx ) != QgsFields::OriginJoin
&& layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression;
mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
mConstraints = layer->fieldConstraints( idx );
mConstraints = layer->fields().at( idx ).constraints();
mConstraint = layer->editFormConfig().constraintExpression( idx );
mConstraintDescription = layer->editFormConfig().constraintDescription( idx );
const QgsEditorWidgetSetup setup = QgsEditorWidgetRegistry::instance()->findBest( layer, layer->fields().field( idx ).name() );
Expand Down
77 changes: 71 additions & 6 deletions src/core/qgsfield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,55 @@ QgsField::Constraints QgsField::constraints() const
return d->constraints;
}

void QgsField::setConstraints( Constraints constraints )
QgsField::ConstraintOrigin QgsField::constraintOrigin( QgsField::Constraint constraint ) const
{
d->constraints = constraints;
if ( !( d->constraints & constraint ) )
return ConstraintOriginNotSet;

return d->constraintOrigins.value( constraint, ConstraintOriginNotSet );
}

void QgsField::setConstraint( QgsField::Constraint constraint, QgsField::ConstraintOrigin origin )
{
if ( origin == ConstraintOriginNotSet )
{
d->constraints &= ~constraint;
d->constraintOrigins.remove( constraint );
}
else
{
d->constraints |= constraint;
d->constraintOrigins.insert( constraint, origin );
}
}

void QgsField::removeConstraint( QgsField::Constraint constraint )
{
d->constraints &= ~constraint;
}

QString QgsField::constraintExpression() const
{
return d->constraints & QgsField::ConstraintExpression ? d->expressionConstraint : QString();
}

QString QgsField::constraintDescription() const
{
return d->expressionConstraintDescription;
}

void QgsField::setConstraintExpression( const QString& expression, const QString& description )
{
if ( expression.isEmpty() )
d->constraints &= ~QgsField::ConstraintExpression;
else
{
d->constraints |= QgsField::ConstraintExpression;
d->constraintOrigins.insert( QgsField::ConstraintExpression, QgsField::ConstraintOriginLayer );
}

d->expressionConstraint = expression;
d->expressionConstraintDescription = description;
}

QString QgsField::alias() const
Expand Down Expand Up @@ -314,15 +360,22 @@ QDataStream& operator<<( QDataStream& out, const QgsField& field )
out << field.alias();
out << field.defaultValueExpression();
out << field.constraints();
out << static_cast< quint32 >( field.constraintOrigin( QgsField::ConstraintNotNull ) );
out << static_cast< quint32 >( field.constraintOrigin( QgsField::ConstraintUnique ) );
out << static_cast< quint32 >( field.constraintOrigin( QgsField::ConstraintExpression ) );
out << field.constraintExpression();
out << field.constraintDescription();
out << static_cast< quint32 >( field.subType() );
return out;
}

QDataStream& operator>>( QDataStream& in, QgsField& field )
{
quint32 type, subType, length, precision, constraints;
QString name, typeName, comment, alias, defaultValueExpression;
in >> name >> type >> typeName >> length >> precision >> comment >> alias >> defaultValueExpression >> constraints >> subType;
quint32 type, subType, length, precision, constraints, originNotNull, originUnique, originExpression;
QString name, typeName, comment, alias, defaultValueExpression, constraintExpression, constraintDescription;
in >> name >> type >> typeName >> length >> precision >> comment >> alias
>> defaultValueExpression >> constraints >> originNotNull >> originUnique >> originExpression >>
constraintExpression >> constraintDescription >> subType;
field.setName( name );
field.setType( static_cast< QVariant::Type >( type ) );
field.setTypeName( typeName );
Expand All @@ -331,7 +384,19 @@ QDataStream& operator>>( QDataStream& in, QgsField& field )
field.setComment( comment );
field.setAlias( alias );
field.setDefaultValueExpression( defaultValueExpression );
field.setConstraints( static_cast< QgsField::Constraints>( constraints ) );
if ( constraints & QgsField::ConstraintNotNull )
field.setConstraint( QgsField::ConstraintNotNull, static_cast< QgsField::ConstraintOrigin>( originNotNull ) );
else
field.removeConstraint( QgsField::ConstraintNotNull );
if ( constraints & QgsField::ConstraintUnique )
field.setConstraint( QgsField::ConstraintUnique, static_cast< QgsField::ConstraintOrigin>( originUnique ) );
else
field.removeConstraint( QgsField::ConstraintUnique );
if ( constraints & QgsField::ConstraintExpression )
field.setConstraint( QgsField::ConstraintExpression, static_cast< QgsField::ConstraintOrigin>( originExpression ) );
else
field.removeConstraint( QgsField::ConstraintExpression );
field.setConstraintExpression( constraintExpression, constraintDescription );
field.setSubType( static_cast< QVariant::Type >( subType ) );
return in;
}
63 changes: 60 additions & 3 deletions src/core/qgsfield.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class CORE_EXPORT QgsField
Q_PROPERTY( QString name READ name WRITE setName )
Q_PROPERTY( QString alias READ alias WRITE setAlias )
Q_PROPERTY( QString defaultValueExpression READ defaultValueExpression WRITE setDefaultValueExpression )
Q_PROPERTY( Constraints constraints READ constraints WRITE setConstraints )
Q_PROPERTY( Constraints constraints READ constraints )

public:

Expand All @@ -66,9 +66,21 @@ class CORE_EXPORT QgsField
{
ConstraintNotNull = 1, //!< Field may not be null
ConstraintUnique = 1 << 1, //!< Field must have a unique value
ConstraintExpression = 1 << 2, //!< Field has an expression constraint set. See constraintExpression().
};
Q_DECLARE_FLAGS( Constraints, Constraint )

/**
* Origin of constraints.
* @note added in QGIS 3.0
*/
enum ConstraintOrigin
{
ConstraintOriginNotSet = 0, //!< Constraint is not set
ConstraintOriginProvider, //!< Constraint was set at data provider
ConstraintOriginLayer, //!< Constraint was set by layer
};

/** Constructor. Constructs a new QgsField object.
* @param name Field name
* @param type Field variant type, currently supported: String / Int / Double
Expand Down Expand Up @@ -225,15 +237,60 @@ class CORE_EXPORT QgsField
* Returns any constraints which are present for the field.
* @note added in QGIS 3.0
* @see setConstraints()
* @see constraintOrigin()
*/
Constraints constraints() const;

/**
* Sets constraints which are present for the field.
* Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint
* is not present on this field.
* @note added in QGIS 3.0
* @see constraints()
*/
ConstraintOrigin constraintOrigin( Constraint constraint ) const;

/**
* Sets a constraint on the field.
* @note added in QGIS 3.0
* @see constraints()
* @see removeConstraint()
*/
void setConstraint( Constraint constraint, ConstraintOrigin origin = ConstraintOriginLayer );

/**
* Removes a constraint from the field.
* @see setConstraint()
* @see constraints()
*/
void removeConstraint( Constraint constraint );

/**
* Returns the constraint expression for the field, if set.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintDescription()
* @see setConstraintExpression()
*/
QString constraintExpression() const;

/**
* Returns the descriptive name for the constraint expression.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintExpression()
* @see setConstraintExpression()
*/
QString constraintDescription() const;

/**
* Set the constraint expression for the field. An optional descriptive name for the constraint
* can also be set. Setting an empty expression will clear any existing expression constraint.
* @note added in QGIS 3.0
* @see constraintExpression()
* @see constraintDescription()
* @see constraints()
*/
void setConstraints( Constraints constraints );
void setConstraintExpression( const QString& expression, const QString& description = QString() );

/** Returns the alias for the field (the friendly displayed name of the field ),
* or an empty string if there is no alias.
Expand Down
17 changes: 16 additions & 1 deletion src/core/qgsfield_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class QgsFieldPrivate : public QSharedData
, alias( other.alias )
, defaultValueExpression( other.defaultValueExpression )
, constraints( other.constraints )
, constraintOrigins( other.constraintOrigins )
, expressionConstraint( other.expressionConstraint )
, expressionConstraintDescription( other.expressionConstraintDescription )
{
}

Expand All @@ -81,7 +84,10 @@ class QgsFieldPrivate : public QSharedData
return (( name == other.name ) && ( type == other.type ) && ( subType == other.subType )
&& ( length == other.length ) && ( precision == other.precision )
&& ( alias == other.alias ) && ( defaultValueExpression == other.defaultValueExpression )
&& ( constraints == other.constraints ) );
&& ( constraints == other.constraints )
&& ( expressionConstraint == other.expressionConstraint )
&& ( expressionConstraintDescription == other.expressionConstraintDescription )
&& ( constraintOrigins == other.constraintOrigins ) );
}

//! Name
Expand Down Expand Up @@ -114,6 +120,15 @@ class QgsFieldPrivate : public QSharedData
//! Constraints
QgsField::Constraints constraints;

//! Origin of field constraints
QHash< QgsField::Constraint, QgsField::ConstraintOrigin > constraintOrigins;

//! Expression constraint
QString expressionConstraint;

//! Expression constraint descriptive name
QString expressionConstraintDescription;

QgsEditorWidgetSetup editorWidgetSetup;
};

Expand Down
7 changes: 5 additions & 2 deletions src/core/qgsvectordataprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,11 @@ QVariant QgsVectorDataProvider::defaultValue( int fieldId ) const

QgsField::Constraints QgsVectorDataProvider::fieldConstraints( int fieldIndex ) const
{
Q_UNUSED( fieldIndex );
return 0;
QgsFields f = fields();
if ( fieldIndex < 0 || fieldIndex >= f.count() )
return 0;

return f.at( fieldIndex ).constraints();
}

bool QgsVectorDataProvider::changeGeometryValues( const QgsGeometryMap &geometry_map )
Expand Down
2 changes: 1 addition & 1 deletion src/core/qgsvectordataprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
* field index.
* @note added in QGIS 3.0
*/
virtual QgsField::Constraints fieldConstraints( int fieldIndex ) const;
QgsField::Constraints fieldConstraints( int fieldIndex ) const;

/**
* Changes geometries of existing features
Expand Down
7 changes: 6 additions & 1 deletion src/core/qgsvectorlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2940,7 +2940,12 @@ void QgsVectorLayer::updateFields()
continue;

// always keep provider constraints intact
mFields[ index ].setConstraints( mFields.at( index ).constraints() | constraintIt.value() );
if ( !( mFields.at( index ).constraints() & QgsField::ConstraintNotNull ) && ( constraintIt.value() & QgsField::ConstraintNotNull ) )
mFields[ index ].setConstraint( QgsField::ConstraintNotNull, QgsField::ConstraintOriginLayer );
if ( !( mFields.at( index ).constraints() & QgsField::ConstraintUnique ) && ( constraintIt.value() & QgsField::ConstraintUnique ) )
mFields[ index ].setConstraint( QgsField::ConstraintUnique, QgsField::ConstraintOriginLayer );
if ( !( mFields.at( index ).constraints() & QgsField::ConstraintExpression ) && ( constraintIt.value() & QgsField::ConstraintExpression ) )
mFields[ index ].setConstraint( QgsField::ConstraintExpression, QgsField::ConstraintOriginLayer );
}

if ( oldFields != mFields )
Expand Down
Loading

0 comments on commit f99ea26

Please sign in to comment.