Move responsibility for storage of constraint expressions to QgsVectorLayer

This commit is contained in:
Nyall Dawson 2016-10-26 09:45:45 +10:00
parent f99ea26bdf
commit 2500d75f5e
14 changed files with 269 additions and 181 deletions

View File

@ -197,52 +197,6 @@ class QgsEditFormConfig
*/
void setReadOnly( int idx, bool readOnly = true );
/**
* Returns the constraint expression of a specific field
*
* @param idx The index of the field
* @return the expression
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
QString constraintExpression( int idx ) const;
/**
* Set the constraint expression for a specific field
*
* @param idx the field index
* @param expression the constraint expression
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
void setConstraintExpression( int idx, const QString& expression );
/**
* Returns the constraint expression description of a specific field.
*
* @param idx The index of the field
* @return The expression description. Will be presented
* to the user in case the constraint fails.
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
QString constraintDescription( int idx ) const;
/**
* Set the constraint expression description for a specific field.
*
* @param idx The index of the field
* @param description The description of the expression. Will be presented
* to the user in case the constraint fails.
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
void setContraintDescription( int idx, const QString& description );
/**
* If this returns true, the widget at the given index will receive its label on the previous line
* while if it returns false, the widget will receive its label on the left hand side.

View File

@ -23,6 +23,7 @@ class QgsField
{
ConstraintNotNull, //!< Field may not be null
ConstraintUnique, //!< Field must have a unique value
ConstraintExpression, //!< Field has an expression constraint set. See constraintExpression().
};
typedef QFlags<QgsField::Constraint> Constraints;

View File

@ -1275,6 +1275,34 @@ class QgsVectorLayer : QgsMapLayer
*/
void setFieldConstraints( int index, QgsField::Constraints constraints );
/**
* Returns the constraint expression for for a specified field index, if set.
* @note added in QGIS 3.0
* @see fieldConstraints()
* @see constraintDescription()
* @see setConstraintExpression()
*/
QString constraintExpression( int index ) const;
/**
* Returns the descriptive name for the constraint expression for a specified field index.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintExpression()
* @see setConstraintExpression()
*/
QString constraintDescription( int index ) const;
/**
* Set the constraint expression for the specified field index. 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 setConstraintExpression( int index, const QString& expression, const QString& description = QString() );
/** Calculates a list of unique values contained within an attribute in the layer. Note that
* in some circumstances when unsaved changes are present for the layer then the returned list
* may contain outdated values (for instance when the attribute value in a saved feature has

View File

@ -977,8 +977,7 @@ void QgsFieldsProperties::apply()
editFormConfig.setReadOnly( i, !cfg.mEditable );
editFormConfig.setLabelOnTop( i, cfg.mLabelOnTop );
editFormConfig.setContraintDescription( i, cfg.mConstraintDescription );
editFormConfig.setConstraintExpression( i, cfg.mConstraint );
mLayer->setConstraintExpression( i, cfg.mConstraint, cfg.mConstraintDescription );
editFormConfig.setWidgetType( name, cfg.mEditorWidgetType );
editFormConfig.setWidgetConfig( name, cfg.mEditorWidgetConfig );
@ -1062,8 +1061,8 @@ QgsFieldsProperties::FieldConfig::FieldConfig( QgsVectorLayer* layer, int idx )
&& layer->fields().fieldOrigin( idx ) != QgsFields::OriginExpression;
mLabelOnTop = layer->editFormConfig().labelOnTop( idx );
mConstraints = layer->fields().at( idx ).constraints();
mConstraint = layer->editFormConfig().constraintExpression( idx );
mConstraintDescription = layer->editFormConfig().constraintDescription( idx );
mConstraint = layer->fields().at( idx ).constraintExpression();
mConstraintDescription = layer->fields().at( idx ).constraintDescription();
const QgsEditorWidgetSetup setup = QgsEditorWidgetRegistry::instance()->findBest( layer, layer->fields().field( idx ).name() );
mEditorWidgetType = setup.type();
mEditorWidgetConfig = setup.config();

View File

@ -182,44 +182,6 @@ bool QgsEditFormConfig::labelOnTop( int idx ) const
return false;
}
QString QgsEditFormConfig::constraintExpression( int idx ) const
{
QString expr;
if ( idx >= 0 && idx < d->mFields.count() )
expr = d->mConstraints.value( d->mFields.at( idx ).name(), QString() );
return expr;
}
void QgsEditFormConfig::setConstraintExpression( int idx, const QString& expression )
{
if ( idx >= 0 && idx < d->mFields.count() )
{
d.detach();
d->mConstraints[ d->mFields.at( idx ).name()] = expression;
}
}
QString QgsEditFormConfig::constraintDescription( int idx ) const
{
QString description;
if ( idx >= 0 && idx < d->mFields.count() )
description = d->mConstraintsDescription[ d->mFields.at( idx ).name()];
return description;
}
void QgsEditFormConfig::setContraintDescription( int idx, const QString &descr )
{
if ( idx >= 0 && idx < d->mFields.count() )
{
d.detach();
d->mConstraintsDescription[ d->mFields.at( idx ).name()] = descr;
}
}
void QgsEditFormConfig::setReadOnly( int idx, bool readOnly )
{
if ( idx >= 0 && idx < d->mFields.count() )

View File

@ -232,52 +232,6 @@ class CORE_EXPORT QgsEditFormConfig
*/
void setReadOnly( int idx, bool readOnly = true );
/**
* Returns the constraint expression of a specific field
*
* @param idx The index of the field
* @return the expression
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
QString constraintExpression( int idx ) const;
/**
* Set the constraint expression for a specific field
*
* @param idx the field index
* @param expression the constraint expression
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
void setConstraintExpression( int idx, const QString& expression );
/**
* Returns the constraint expression description of a specific field.
*
* @param idx The index of the field
* @return The expression description. Will be presented
* to the user in case the constraint fails.
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
QString constraintDescription( int idx ) const;
/**
* Set the constraint expression description for a specific field.
*
* @param idx The index of the field
* @param description The description of the expression. Will be presented
* to the user in case the constraint fails.
*
* @note added in QGIS 2.16
* @note renamed in QGIS 3.0
*/
void setContraintDescription( int idx, const QString& description );
/**
* If this returns true, the widget at the given index will receive its label on the previous line
* while if it returns false, the widget will receive its label on the left hand side.

View File

@ -38,8 +38,6 @@ class QgsEditFormConfigPrivate : public QSharedData
: QSharedData( o )
, mInvisibleRootContainer( static_cast<QgsAttributeEditorContainer*>( o.mInvisibleRootContainer->clone( nullptr ) ) )
, mConfiguredRootContainer( o.mConfiguredRootContainer )
, mConstraints( o.mConstraints )
, mConstraintsDescription( o.mConstraintsDescription )
, mFieldEditables( o.mFieldEditables )
, mLabelOnTop( o.mLabelOnTop )
, mEditorWidgetTypes( o.mEditorWidgetTypes )
@ -64,8 +62,6 @@ class QgsEditFormConfigPrivate : public QSharedData
//! This flag is set if the root container was configured by the user
bool mConfiguredRootContainer;
QMap< QString, QString> mConstraints;
QMap< QString, QString> mConstraintsDescription;
QMap< QString, bool> mFieldEditables;
QMap< QString, bool> mLabelOnTop;

View File

@ -1459,6 +1459,24 @@ bool QgsVectorLayer::readXml( const QDomNode& layer_node )
mFieldConstraints.insert( field, static_cast< QgsField::Constraints >( constraints ) );
}
}
mFieldConstraintExpressions.clear();
QDomNode constraintExpressionsNode = layer_node.namedItem( "constraintExpressions" );
if ( !constraintExpressionsNode.isNull() )
{
QDomNodeList constraintNodeList = constraintExpressionsNode.toElement().elementsByTagName( "constraint" );
for ( int i = 0; i < constraintNodeList.size(); ++i )
{
QDomElement constraintElem = constraintNodeList.at( i ).toElement();
QString field = constraintElem.attribute( "field", QString() );
QString exp = constraintElem.attribute( "exp", QString() );
QString desc = constraintElem.attribute( "desc", QString() );
if ( field.isEmpty() || exp.isEmpty() )
continue;
mFieldConstraintExpressions.insert( field, qMakePair( exp, desc ) );
}
}
updateFields();
@ -1677,6 +1695,19 @@ bool QgsVectorLayer::writeXml( QDomNode & layer_node,
}
layer_node.appendChild( constraintsElem );
// constraint expressions
QDomElement constraintExpressionsElem = document.createElement( "constraintExpressions" );
Q_FOREACH ( const QgsField& field, mFields )
{
QDomElement constraintExpressionElem = document.createElement( "constraint" );
constraintExpressionElem.setAttribute( "field", field.name() );
constraintExpressionElem.setAttribute( "exp", field.constraintExpression() );
constraintExpressionElem.setAttribute( "desc", field.constraintDescription() );
constraintExpressionsElem.appendChild( constraintExpressionElem );
}
layer_node.appendChild( constraintExpressionsElem );
// change dependencies
QDomElement dataDependenciesElement = document.createElement( QStringLiteral( "dataDependencies" ) );
Q_FOREACH ( const QgsMapLayerDependency& dep, dependencies() )
@ -2948,6 +2979,20 @@ void QgsVectorLayer::updateFields()
mFields[ index ].setConstraint( QgsField::ConstraintExpression, QgsField::ConstraintOriginLayer );
}
QMap< QString, QPair< QString, QString > >::const_iterator constraintExpIt = mFieldConstraintExpressions.constBegin();
for ( ; constraintExpIt != mFieldConstraintExpressions.constEnd(); ++constraintExpIt )
{
int index = mFields.lookupField( constraintExpIt.key() );
if ( index < 0 )
continue;
// always keep provider constraints intact
if ( mFields.at( index ).constraintOrigin( QgsField::ConstraintExpression ) == QgsField::ConstraintOriginProvider )
continue;
mFields[ index ].setConstraintExpression( constraintExpIt.value().first, constraintExpIt.value().second );
}
if ( oldFields != mFields )
{
emit updatedFields();
@ -4268,3 +4313,35 @@ void QgsVectorLayer::setFieldConstraints( int index, QgsField::Constraints const
}
updateFields();
}
QString QgsVectorLayer::constraintExpression( int index ) const
{
if ( index < 0 || index >= mFields.count() )
return QString();
return mFields.at( index ).constraintExpression();
}
QString QgsVectorLayer::constraintDescription( int index ) const
{
if ( index < 0 || index >= mFields.count() )
return QString();
return mFields.at( index ).constraintDescription();
}
void QgsVectorLayer::setConstraintExpression( int index, const QString& expression, const QString& description )
{
if ( index < 0 || index >= mFields.count() )
return;
if ( expression.isEmpty() )
{
mFieldConstraintExpressions.remove( mFields.at( index ).name() );
}
else
{
mFieldConstraintExpressions.insert( mFields.at( index ).name(), qMakePair( expression, description ) );
}
updateFields();
}

View File

@ -1415,6 +1415,34 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
void setFieldConstraints( int index, QgsField::Constraints constraints );
/**
* Returns the constraint expression for for a specified field index, if set.
* @note added in QGIS 3.0
* @see fieldConstraints()
* @see constraintDescription()
* @see setConstraintExpression()
*/
QString constraintExpression( int index ) const;
/**
* Returns the descriptive name for the constraint expression for a specified field index.
* @note added in QGIS 3.0
* @see constraints()
* @see constraintExpression()
* @see setConstraintExpression()
*/
QString constraintDescription( int index ) const;
/**
* Set the constraint expression for the specified field index. 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 setConstraintExpression( int index, const QString& expression, const QString& description = QString() );
/** Calculates a list of unique values contained within an attribute in the layer. Note that
* in some circumstances when unsaved changes are present for the layer then the returned list
* may contain outdated values (for instance when the attribute value in a saved feature has
@ -1955,6 +1983,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! Map which stores constraints for fields
QMap< QString, QgsField::Constraints > mFieldConstraints;
//! Map which stores expression constraints for fields. Value is a pair of expression/description.
QMap< QString, QPair< QString, QString > > mFieldConstraintExpressions;
//! Holds the configuration for the edit form
QgsEditFormConfig mEditFormConfig;

View File

@ -268,8 +268,12 @@ void QgsEditorWidgetRegistry::readMapLayer( QgsMapLayer* mapLayer, const QDomEle
// upgrade from older config
vectorLayer->setFieldConstraints( idx, vectorLayer->fieldConstraints( idx ) | QgsField::ConstraintNotNull );
}
formConfig.setConstraintExpression( idx, ewv2CfgElem.attribute( QStringLiteral( "constraint" ), QString() ) );
formConfig.setContraintDescription( idx, ewv2CfgElem.attribute( QStringLiteral( "constraintDescription" ), QString() ) );
if ( !ewv2CfgElem.attribute( QStringLiteral( "constraint" ), QString() ).isEmpty() )
{
// upgrade from older config
vectorLayer->setConstraintExpression( idx, ewv2CfgElem.attribute( QStringLiteral( "constraint" ), QString() ),
ewv2CfgElem.attribute( QStringLiteral( "constraintDescription" ), QString() ) );
}
formConfig.setWidgetConfig( name, cfg );
}
@ -323,8 +327,6 @@ void QgsEditorWidgetRegistry::writeMapLayer( QgsMapLayer* mapLayer, QDomElement&
QDomElement ewv2CfgElem = doc.createElement( QStringLiteral( "widgetv2config" ) );
ewv2CfgElem.setAttribute( QStringLiteral( "fieldEditable" ), !vectorLayer->editFormConfig().readOnly( idx ) );
ewv2CfgElem.setAttribute( QStringLiteral( "labelOnTop" ), vectorLayer->editFormConfig().labelOnTop( idx ) );
ewv2CfgElem.setAttribute( QStringLiteral( "constraint" ), vectorLayer->editFormConfig().constraintExpression( idx ) );
ewv2CfgElem.setAttribute( QStringLiteral( "constraintDescription" ), vectorLayer->editFormConfig().constraintDescription( idx ) );
mWidgetFactories[widgetType]->writeConfig( vectorLayer->editFormConfig().widgetConfig( field.name() ), ewv2CfgElem, doc, vectorLayer, idx );

View File

@ -109,10 +109,11 @@ void QgsEditorWidgetWrapper::updateConstraintWidgetStatus( bool constraintValid
void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
{
bool toEmit( false );
QString expression = layer()->editFormConfig().constraintExpression( mFieldIdx );
QgsField field = layer()->fields().at( mFieldIdx );
QString expression = field.constraintExpression();
QStringList expressions, descriptions;
QVariant value = ft.attribute( mFieldIdx );
QString fieldName = ft.fields().count() > mFieldIdx ? ft.fields().field( mFieldIdx ).name() : QString();
mConstraintFailureReason.clear();
@ -121,7 +122,7 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
if ( ! expression.isEmpty() )
{
expressions << expression;
descriptions << layer()->editFormConfig().constraintDescription( mFieldIdx );
descriptions << field.constraintDescription();
QgsExpressionContext context = layer()->createExpressionContext();
context.setFeature( ft );
@ -140,7 +141,7 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
}
else if ( ! mValidConstraint )
{
errors << tr( "%1 check failed" ).arg( layer()->editFormConfig().constraintDescription( mFieldIdx ) );
errors << tr( "%1 check failed" ).arg( field.constraintDescription() );
}
toEmit = true;
@ -148,12 +149,12 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
else
mValidConstraint = true;
if ( layer()->fields().at( mFieldIdx ).constraints() & QgsField::ConstraintNotNull )
if ( field.constraints() & QgsField::ConstraintNotNull )
{
descriptions << QStringLiteral( "NotNull" );
if ( !expression.isEmpty() )
{
expressions << fieldName + " IS NOT NULL";
expressions << field.name() + " IS NOT NULL";
}
else
{
@ -170,12 +171,12 @@ void QgsEditorWidgetWrapper::updateConstraint( const QgsFeature &ft )
toEmit = true;
}
if ( layer()->fields().at( mFieldIdx ).constraints() & QgsField::ConstraintUnique )
if ( field.constraints() & QgsField::ConstraintUnique )
{
descriptions << QStringLiteral( "Unique" );
if ( !expression.isEmpty() )
{
expressions << fieldName + " IS UNIQUE";
expressions << field.name() + " IS UNIQUE";
}
else
{

View File

@ -940,7 +940,7 @@ QList<QgsEditorWidgetWrapper*> QgsAttributeForm::constraintDependencies( QgsEdit
if ( name != ewwName )
{
// get expression and referencedColumns
QgsExpression expr = eww->layer()->editFormConfig().constraintExpression( eww->fieldIdx() );
QgsExpression expr = eww->layer()->fields().at( eww->fieldIdx() ).constraintExpression();
Q_FOREACH ( const QString& colName, expr.referencedColumns() )
{

View File

@ -78,14 +78,11 @@ void TestQgsAttributeForm::testFieldConstraint()
form.setFeature( ft );
// testing stuff
QSignalSpy spy( &form, SIGNAL( attributeChanged( QString, QVariant ) ) );
QString validLabel = QStringLiteral( "col0<font color=\"green\">*</font>" );
QString invalidLabel = QStringLiteral( "col0<font color=\"red\">*</font>" );
// set constraint
QgsEditFormConfig config = layer->editFormConfig();
config.setConstraintExpression( 0, QString() );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QString() );
// get wrapper
QgsEditorWidgetWrapper *ww;
@ -96,8 +93,13 @@ void TestQgsAttributeForm::testFieldConstraint()
QCOMPARE( label->text(), QString( "col0" ) );
// set a not null constraint
config.setConstraintExpression( 0, QStringLiteral( "col0 is not null" ) );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QStringLiteral( "col0 is not null" ) );
// build a form for this feature
QgsAttributeForm form2( layer );
form2.setFeature( ft );
QSignalSpy spy( &form2, SIGNAL( attributeChanged( QString, QVariant ) ) );
ww = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[0] );
label = form2.mBuddyMap.value( ww->widget() );
// set value to 1
ww->setValue( 1 );
@ -131,12 +133,10 @@ void TestQgsAttributeForm::testFieldMultiConstraints()
ft.setAttribute( QStringLiteral( "col3" ), 3 );
// set constraints for each field
QgsEditFormConfig config = layer->editFormConfig();
config.setConstraintExpression( 0, QString() );
config.setConstraintExpression( 1, QString() );
config.setConstraintExpression( 2, QString() );
config.setConstraintExpression( 3, QString() );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QString() );
layer->setConstraintExpression( 1, QString() );
layer->setConstraintExpression( 2, QString() );
layer->setConstraintExpression( 3, QString() );
// build a form for this feature
QgsAttributeForm form( layer );
@ -167,15 +167,26 @@ void TestQgsAttributeForm::testFieldMultiConstraints()
QCOMPARE( label3->text(), QString( "col3" ) );
// update constraint
config.setConstraintExpression( 0, QStringLiteral( "col0 < (col1 * col2)" ) );
config.setConstraintExpression( 1, QString() );
config.setConstraintExpression( 2, QString() );
config.setConstraintExpression( 3, QStringLiteral( "col0 = 2" ) );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QStringLiteral( "col0 < (col1 * col2)" ) );
layer->setConstraintExpression( 1, QString() );
layer->setConstraintExpression( 2, QString() );
layer->setConstraintExpression( 3, QStringLiteral( "col0 = 2" ) );
QgsAttributeForm form2( layer );
form2.setFeature( ft );
ww0 = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[0] );
ww1 = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[1] );
ww2 = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[2] );
ww3 = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[3] );
label0 = form2.mBuddyMap.value( ww0->widget() );
label1 = form2.mBuddyMap.value( ww1->widget() );
label2 = form2.mBuddyMap.value( ww2->widget() );
label3 = form2.mBuddyMap.value( ww3->widget() );
QSignalSpy spy2( &form2, SIGNAL( attributeChanged( QString, QVariant ) ) );
// change value
ww0->setValue( 2 ); // update col0
QCOMPARE( spy.count(), 2 );
QCOMPARE( spy2.count(), 2 );
QCOMPARE( label0->text(), QString( "col0" + inv ) ); // 2 < ( 1 + 2 )
QCOMPARE( label1->text(), QString( "col1" ) );
@ -183,9 +194,9 @@ void TestQgsAttributeForm::testFieldMultiConstraints()
QCOMPARE( label3->text(), QString( "col3" + val ) ); // 2 = 2
// change value
spy.clear();
spy2.clear();
ww0->setValue( 1 ); // update col0
QCOMPARE( spy.count(), 2 );
QCOMPARE( spy2.count(), 2 );
QCOMPARE( label0->text(), QString( "col0" + val ) ); // 1 < ( 1 + 2 )
QCOMPARE( label1->text(), QString( "col1" ) );
@ -205,9 +216,7 @@ void TestQgsAttributeForm::testOKButtonStatus()
ft.setValid( true );
// set constraint
QgsEditFormConfig config = layer->editFormConfig();
config.setConstraintExpression( 0, QString() );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QString() );
// build a form for this feature
QgsAttributeForm form( layer );
@ -235,14 +244,21 @@ void TestQgsAttributeForm::testOKButtonStatus()
QCOMPARE( okButton->isEnabled(), true );
// invalid constraint and editable layer : OK button disabled
config.setConstraintExpression( 0, QStringLiteral( "col0 = 0" ) );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QStringLiteral( "col0 = 0" ) );
QgsAttributeForm form2( layer );
form2.setFeature( ft );
ww = qobject_cast<QgsEditorWidgetWrapper*>( form2.mWidgets[0] );
okButton = form2.mButtonBox->button( QDialogButtonBox::Ok );
ww->setValue( 1 );
QCOMPARE( okButton->isEnabled(), false );
// valid constraint and editable layer : OK button enabled
config.setConstraintExpression( 0, QStringLiteral( "col0 = 2" ) );
layer->setEditFormConfig( config );
layer->setConstraintExpression( 0, QStringLiteral( "col0 = 2" ) );
QgsAttributeForm form3( layer );
form3.setFeature( ft );
ww = qobject_cast<QgsEditorWidgetWrapper*>( form3.mWidgets[0] );
okButton = form3.mButtonBox->button( QDialogButtonBox::Ok );
ww->setValue( 2 );
QCOMPARE( okButton->isEnabled(), true );

View File

@ -1840,12 +1840,79 @@ class TestQgsVectorLayer(unittest.TestCase):
self.assertEqual(layer3.fieldConstraints(0), QgsField.ConstraintNotNull)
self.assertEqual(layer3.fieldConstraints(1), QgsField.ConstraintNotNull | QgsField.ConstraintUnique)
self.assertEqual(layer3.fields().at(0).constraints(), QgsField.ConstraintNotNull)
self.assertEqual(layer.fields().at(0).constraintOrigin(QgsField.ConstraintNotNull),
self.assertEqual(layer3.fields().at(0).constraintOrigin(QgsField.ConstraintNotNull),
QgsField.ConstraintOriginLayer)
self.assertEqual(layer3.fields().at(1).constraints(), QgsField.ConstraintNotNull | QgsField.ConstraintUnique)
self.assertEqual(layer.fields().at(1).constraintOrigin(QgsField.ConstraintNotNull),
self.assertEqual(layer3.fields().at(1).constraintOrigin(QgsField.ConstraintNotNull),
QgsField.ConstraintOriginLayer)
self.assertEqual(layer.fields().at(1).constraintOrigin(QgsField.ConstraintUnique),
self.assertEqual(layer3.fields().at(1).constraintOrigin(QgsField.ConstraintUnique),
QgsField.ConstraintOriginLayer)
def testGetSetConstraintExpressions(self):
""" test getting and setting field constraint expressions """
layer = createLayerWithOnePoint()
self.assertFalse(layer.constraintExpression(0))
self.assertFalse(layer.constraintExpression(1))
self.assertFalse(layer.constraintExpression(2))
layer.setConstraintExpression(0, '1+2')
self.assertEqual(layer.constraintExpression(0), '1+2')
self.assertFalse(layer.constraintExpression(1))
self.assertFalse(layer.constraintExpression(2))
self.assertEqual(layer.fields().at(0).constraintExpression(), '1+2')
layer.setConstraintExpression(1, '3+4', 'desc')
self.assertEqual(layer.constraintExpression(0), '1+2')
self.assertEqual(layer.constraintExpression(1), '3+4')
self.assertEqual(layer.constraintDescription(1), 'desc')
self.assertFalse(layer.constraintExpression(2))
self.assertEqual(layer.fields().at(0).constraintExpression(), '1+2')
self.assertEqual(layer.fields().at(1).constraintExpression(), '3+4')
self.assertEqual(layer.fields().at(1).constraintDescription(), 'desc')
layer.setConstraintExpression(1, None)
self.assertEqual(layer.constraintExpression(0), '1+2')
self.assertFalse(layer.constraintExpression(1))
self.assertFalse(layer.constraintExpression(2))
self.assertEqual(layer.fields().at(0).constraintExpression(), '1+2')
self.assertFalse(layer.fields().at(1).constraintExpression())
def testSaveRestoreConstraintExpressions(self):
""" test saving and restoring constraint expressions from xml"""
layer = createLayerWithOnePoint()
# no constraints
doc = QDomDocument("testdoc")
elem = doc.createElement("maplayer")
self.assertTrue(layer.writeXml(elem, doc))
layer2 = createLayerWithOnePoint()
self.assertTrue(layer2.readXml(elem))
self.assertFalse(layer2.constraintExpression(0))
self.assertFalse(layer2.constraintExpression(1))
# set some constraints
layer.setConstraintExpression(0, '1+2')
layer.setConstraintExpression(1, '3+4', 'desc')
doc = QDomDocument("testdoc")
elem = doc.createElement("maplayer")
self.assertTrue(layer.writeXml(elem, doc))
layer3 = createLayerWithOnePoint()
self.assertTrue(layer3.readXml(elem))
self.assertEqual(layer3.constraintExpression(0), '1+2')
self.assertEqual(layer3.constraintExpression(1), '3+4')
self.assertEqual(layer3.constraintDescription(1), 'desc')
self.assertEqual(layer3.fields().at(0).constraintExpression(), '1+2')
self.assertEqual(layer3.fields().at(1).constraintExpression(), '3+4')
self.assertEqual(layer3.fields().at(1).constraintDescription(), 'desc')
self.assertEqual(layer3.fields().at(0).constraints(), QgsField.ConstraintExpression)
self.assertEqual(layer3.fields().at(1).constraints(), QgsField.ConstraintExpression)
self.assertEqual(layer3.fields().at(0).constraintOrigin(QgsField.ConstraintExpression),
QgsField.ConstraintOriginLayer)
self.assertEqual(layer3.fields().at(1).constraintOrigin(QgsField.ConstraintExpression),
QgsField.ConstraintOriginLayer)
def testGetFeatureLimitWithEdits(self):