mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
New method QgsVectorLayerUtils::createUniqueValue
Returns a new unique attribute value for a layer. For numeric fields this is the max attribute value + 1, for strings we attempt to create a unique value by append _1, _2, etc to either a specified 'seed' value, or failing that to the end of the value of that field from the first feature in the layer.
This commit is contained in:
parent
4682eaf6eb
commit
747097d43d
@ -16,9 +16,17 @@ class QgsVectorLayerUtils
|
||||
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
|
||||
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
|
||||
* with IDs within this list are ignored when testing for existance of the value.
|
||||
* @see createUniqueValue()
|
||||
*/
|
||||
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );
|
||||
|
||||
/**
|
||||
* Returns a new attribute value for the specified field index which is guaranteed to be unique. The optional seed
|
||||
* value can be used as a basis for generated values.
|
||||
* @see valueExists()
|
||||
*/
|
||||
static QVariant createUniqueValue( const QgsVectorLayer* layer, int fieldIndex, const QVariant& seed = QVariant() );
|
||||
|
||||
/**
|
||||
* Tests an attribute value to check whether it passes all constraints which are present on the corresponding field.
|
||||
* Returns true if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "qgsvectorlayerutils.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include <QRegularExpression>
|
||||
|
||||
bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds )
|
||||
{
|
||||
@ -65,6 +66,86 @@ bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer* layer, int fieldInd
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer* layer, int fieldIndex, const QVariant& seed )
|
||||
{
|
||||
if ( !layer )
|
||||
return QVariant();
|
||||
|
||||
QgsFields fields = layer->fields();
|
||||
|
||||
if ( fieldIndex < 0 || fieldIndex >= fields.count() )
|
||||
return QVariant();
|
||||
|
||||
QgsField field = fields.at( fieldIndex );
|
||||
|
||||
if ( field.isNumeric() )
|
||||
{
|
||||
QVariant maxVal = layer->maximumValue( fieldIndex );
|
||||
QVariant newVar( maxVal.toLongLong() + 1 );
|
||||
if ( field.convertCompatible( newVar ) )
|
||||
return newVar;
|
||||
else
|
||||
return QVariant();
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( field.type() )
|
||||
{
|
||||
case QVariant::String:
|
||||
{
|
||||
QString base;
|
||||
if ( seed.isValid() )
|
||||
base = seed.toString();
|
||||
|
||||
if ( !base.isEmpty() )
|
||||
{
|
||||
// strip any existing _1, _2 from the seed
|
||||
QRegularExpression rx( "(.*)_\\d+" );
|
||||
QRegularExpressionMatch match = rx.match( base );
|
||||
if ( match.hasMatch() )
|
||||
{
|
||||
base = match.captured( 1 );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// no base seed - fetch first value from layer
|
||||
QgsFeatureRequest req;
|
||||
req.setLimit( 1 );
|
||||
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
|
||||
req.setFlags( QgsFeatureRequest::NoGeometry );
|
||||
QgsFeature f;
|
||||
layer->getFeatures( req ).nextFeature( f );
|
||||
base = f.attribute( fieldIndex ).toString();
|
||||
}
|
||||
|
||||
// try variants like base_1, base_2, etc until a new value found
|
||||
QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
|
||||
|
||||
// might already be unique
|
||||
if ( !base.isEmpty() && !vals.contains( base ) )
|
||||
return base;
|
||||
|
||||
for ( int i = 1; i < 10000; ++i )
|
||||
{
|
||||
QString testVal = base + '_' + QString::number( i );
|
||||
if ( !vals.contains( testVal ) )
|
||||
return testVal;
|
||||
}
|
||||
|
||||
// failed
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
default:
|
||||
// todo other types - dates? times?
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer* layer, const QgsFeature& feature, int attributeIndex, QStringList& errors,
|
||||
QgsFieldConstraints::ConstraintStrength strength, QgsFieldConstraints::ConstraintOrigin origin )
|
||||
{
|
||||
|
@ -33,9 +33,17 @@ class CORE_EXPORT QgsVectorLayerUtils
|
||||
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
|
||||
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
|
||||
* with IDs within this list are ignored when testing for existance of the value.
|
||||
* @see createUniqueValue()
|
||||
*/
|
||||
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );
|
||||
|
||||
/**
|
||||
* Returns a new attribute value for the specified field index which is guaranteed to be unique. The optional seed
|
||||
* value can be used as a basis for generated values.
|
||||
* @see valueExists()
|
||||
*/
|
||||
static QVariant createUniqueValue( const QgsVectorLayer* layer, int fieldIndex, const QVariant& seed = QVariant() );
|
||||
|
||||
/**
|
||||
* Tests an attribute value to check whether it passes all constraints which are present on the corresponding field.
|
||||
* Returns true if the attribute value is valid for the field. Any constraint failures will be reported in the errors argument.
|
||||
@ -45,6 +53,7 @@ class CORE_EXPORT QgsVectorLayerUtils
|
||||
QgsFieldConstraints::ConstraintStrength strength = QgsFieldConstraints::ConstraintStrengthNotSet,
|
||||
QgsFieldConstraints::ConstraintOrigin origin = QgsFieldConstraints::ConstraintOriginNotSet );
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // QGSVECTORLAYERUTILS_H
|
||||
|
@ -178,6 +178,38 @@ class TestQgsVectorLayerUtils(unittest.TestCase):
|
||||
self.assertEqual(len(errors), 2)
|
||||
print(errors)
|
||||
|
||||
def testCreateUniqueValue(self):
|
||||
""" test creating a unique value """
|
||||
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer&field=flddbl:double",
|
||||
"addfeat", "memory")
|
||||
# add a bunch of features
|
||||
f = QgsFeature()
|
||||
f.setAttributes(["test", 123, 1.0])
|
||||
f1 = QgsFeature(2)
|
||||
f1.setAttributes(["test_1", 124, 1.1])
|
||||
f2 = QgsFeature(3)
|
||||
f2.setAttributes(["test_2", 125, 2.4])
|
||||
f3 = QgsFeature(4)
|
||||
f3.setAttributes(["test_3", 126, 1.7])
|
||||
f4 = QgsFeature(5)
|
||||
f4.setAttributes(["superpig", 127, 0.8])
|
||||
self.assertTrue(layer.dataProvider().addFeatures([f, f1, f2, f3, f4]))
|
||||
|
||||
# bad field indices
|
||||
self.assertFalse(QgsVectorLayerUtils.createUniqueValue(layer, -10))
|
||||
self.assertFalse(QgsVectorLayerUtils.createUniqueValue(layer, 10))
|
||||
|
||||
# integer field
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 1), 128)
|
||||
|
||||
# double field
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 2), 3.0)
|
||||
|
||||
# string field
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0), 'test_4')
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'test_1'), 'test_4')
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'seed'), 'seed')
|
||||
self.assertEqual(QgsVectorLayerUtils.createUniqueValue(layer, 0, 'superpig'), 'superpig_1')
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user