Skip to content

Commit 58cc890

Browse files
committed
[FEATURE] Add support for attribute renaming to QgsVectorDataProvider
Implemented in memory layer provider only, not yet supported in edit buffer or configurable in GUI
1 parent d40554b commit 58cc890

File tree

6 files changed

+95
-6
lines changed

6 files changed

+95
-6
lines changed

python/core/qgsvectordataprovider.sip

+11-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ class QgsVectorDataProvider : QgsDataProvider
5454
/** Supports joint updates for attributes and geometry
5555
* Providers supporting this should still define ChangeGeometries | ChangeAttributeValues
5656
*/
57-
ChangeFeatures
57+
ChangeFeatures,
58+
/** Supports renaming attributes (fields). Added in QGIS 2.16 */
59+
RenameAttributes,
5860
};
5961

6062
/** Bitmask of all provider's editing capabilities */
@@ -205,6 +207,14 @@ class QgsVectorDataProvider : QgsDataProvider
205207
*/
206208
virtual bool deleteAttributes( const QSet<int> &attributes );
207209

210+
/**
211+
* Renames existing attributes.
212+
* @param renamedAttributes map of attribute index to new attribute name
213+
* @return true in case of success and false in case of failure
214+
* @note added in QGIS 2.16
215+
*/
216+
virtual bool renameAttributes( const QgsFieldNameMap& renamedAttributes );
217+
208218
/**
209219
* Changes attribute values of existing features.
210220
* @param attr_map a map containing changed attributes

src/core/qgsvectordataprovider.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ bool QgsVectorDataProvider::deleteAttributes( const QgsAttributeIds &attributes
8181
return false;
8282
}
8383

84+
bool QgsVectorDataProvider::renameAttributes( const QgsFieldNameMap& renamedAttributes )
85+
{
86+
Q_UNUSED( renamedAttributes );
87+
return false;
88+
}
89+
8490
bool QgsVectorDataProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
8591
{
8692
Q_UNUSED( attr_map );

src/core/qgsvectordataprovider.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,15 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
102102
/** Supports joint updates for attributes and geometry
103103
* Providers supporting this should still define ChangeGeometries | ChangeAttributeValues
104104
*/
105-
ChangeFeatures = 1 << 18
105+
ChangeFeatures = 1 << 18,
106+
/** Supports renaming attributes (fields). Added in QGIS 2.16 */
107+
RenameAttributes = 1 << 19,
106108
};
107109

108110
/** Bitmask of all provider's editing capabilities */
109111
const static int EditingCapabilities = AddFeatures | DeleteFeatures |
110-
ChangeAttributeValues | ChangeGeometries | AddAttributes | DeleteAttributes;
112+
ChangeAttributeValues | ChangeGeometries | AddAttributes | DeleteAttributes |
113+
RenameAttributes;
111114

112115
/**
113116
* Constructor of the vector provider
@@ -254,6 +257,14 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
254257
*/
255258
virtual bool deleteAttributes( const QgsAttributeIds &attributes );
256259

260+
/**
261+
* Renames existing attributes.
262+
* @param renamedAttributes map of attribute index to new attribute name
263+
* @return true in case of success and false in case of failure
264+
* @note added in QGIS 2.16
265+
*/
266+
virtual bool renameAttributes( const QgsFieldNameMap& renamedAttributes );
267+
257268
/**
258269
* Changes attribute values of existing features.
259270
* @param attr_map a map containing changed attributes

src/providers/memory/qgsmemoryprovider.cpp

+25-2
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,6 @@ bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
375375
{
376376
for ( QList<QgsField>::const_iterator it = attributes.begin(); it != attributes.end(); ++it )
377377
{
378-
// Why are attributes restricted to int,double and string only?
379378
switch ( it->type() )
380379
{
381380
case QVariant::Int:
@@ -404,6 +403,30 @@ bool QgsMemoryProvider::addAttributes( const QList<QgsField> &attributes )
404403
return true;
405404
}
406405

406+
bool QgsMemoryProvider::renameAttributes( const QgsFieldNameMap& renamedAttributes )
407+
{
408+
QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
409+
bool result = true;
410+
for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
411+
{
412+
int fieldIndex = renameIt.key();
413+
if ( fieldIndex < 0 || fieldIndex >= mFields.count() )
414+
{
415+
result = false;
416+
continue;
417+
}
418+
if ( mFields.indexFromName( renameIt.value() ) >= 0 )
419+
{
420+
//field name already in use
421+
result = false;
422+
continue;
423+
}
424+
425+
mFields[ fieldIndex ].setName( renameIt.value() );
426+
}
427+
return result;
428+
}
429+
407430
bool QgsMemoryProvider::deleteAttributes( const QgsAttributeIds& attributes )
408431
{
409432
QList<int> attrIdx = attributes.toList();
@@ -506,7 +529,7 @@ bool QgsMemoryProvider::createSpatialIndex()
506529
int QgsMemoryProvider::capabilities() const
507530
{
508531
return AddFeatures | DeleteFeatures | ChangeGeometries |
509-
ChangeAttributeValues | AddAttributes | DeleteAttributes | CreateSpatialIndex |
532+
ChangeAttributeValues | AddAttributes | DeleteAttributes | RenameAttributes | CreateSpatialIndex |
510533
SelectAtId | SelectGeometryAtId | CircularGeometries;
511534
}
512535

src/providers/memory/qgsmemoryprovider.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ class QgsMemoryProvider : public QgsVectorDataProvider
8989
*/
9090
virtual bool addAttributes( const QList<QgsField> &attributes ) override;
9191

92+
virtual bool renameAttributes( const QgsFieldNameMap& renamedAttributes ) override;
93+
9294
/**
9395
* Deletes existing attributes
9496
* @param attributes a set containing names of attributes
@@ -132,7 +134,6 @@ class QgsMemoryProvider : public QgsVectorDataProvider
132134
*/
133135
virtual int capabilities() const override;
134136

135-
136137
/* Implementation of functions from QgsDataProvider */
137138

138139
/**

tests/src/python/test_provider_memory.py

+38
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,44 @@ def testSaveFields(self):
262262
for f in myFields:
263263
assert f == importedFields.field(f.name())
264264

265+
def testRenameAttributes(self):
266+
layer = QgsVectorLayer("Point", "test", "memory")
267+
provider = layer.dataProvider()
268+
269+
res = provider.addAttributes([QgsField("name", QVariant.String, ),
270+
QgsField("age", QVariant.Int),
271+
QgsField("size", QVariant.Double)])
272+
layer.updateFields()
273+
assert res, "Failed to add attributes"
274+
ft = QgsFeature()
275+
ft.setGeometry(QgsGeometry.fromPoint(QgsPoint(10, 10)))
276+
ft.setAttributes(["Johny",
277+
20,
278+
0.3])
279+
res, t = provider.addFeatures([ft])
280+
281+
# bad rename
282+
self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
283+
self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
284+
# already exists
285+
self.assertFalse(provider.renameAttributes({1: 'name'}))
286+
287+
# rename one field
288+
self.assertTrue(provider.renameAttributes({1: 'this_is_the_new_age'}))
289+
self.assertEqual(provider.fields().at(1).name(), 'this_is_the_new_age')
290+
layer.updateFields()
291+
fet = next(layer.getFeatures())
292+
self.assertEqual(fet.fields()[1].name(), 'this_is_the_new_age')
293+
294+
# rename two fields
295+
self.assertTrue(provider.renameAttributes({1: 'mapinfo_is_the_stone_age', 2: 'super_size'}))
296+
self.assertEqual(provider.fields().at(1).name(), 'mapinfo_is_the_stone_age')
297+
self.assertEqual(provider.fields().at(2).name(), 'super_size')
298+
layer.updateFields()
299+
fet = next(layer.getFeatures())
300+
self.assertEqual(fet.fields()[1].name(), 'mapinfo_is_the_stone_age')
301+
self.assertEqual(fet.fields()[2].name(), 'super_size')
302+
265303

266304
class TestPyQgsMemoryProviderIndexed(unittest.TestCase, ProviderTestCase):
267305

0 commit comments

Comments
 (0)