Skip to content

Commit b7d0fd6

Browse files
committedNov 2, 2016
New class QgsVectorLayerUtils
Contains static helper methods for working with vector layers. Initially only contains a method to test whether a value exists within a layer's attributes.
1 parent 3e40f80 commit b7d0fd6

File tree

8 files changed

+207
-0
lines changed

8 files changed

+207
-0
lines changed
 

‎python/core/core.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@
148148
%Include qgsvectorlayerimport.sip
149149
%Include qgsvectorlayerjoinbuffer.sip
150150
%Include qgsvectorlayerundocommand.sip
151+
%Include qgsvectorlayerutils.sip
151152
%Include qgsvectorsimplifymethod.sip
152153

153154
%Include qgscachedfeatureiterator.sip

‎python/core/qgsvectorlayerutils.sip

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
/** \ingroup core
3+
* \class QgsVectorLayerUtils
4+
* \brief Contains utility methods for working with QgsVectorLayers.
5+
*
6+
* \note Added in version 3.0
7+
*/
8+
class QgsVectorLayerUtils
9+
{
10+
%TypeHeaderCode
11+
#include <qgsvectorlayerutils.h>
12+
%End
13+
public:
14+
15+
/**
16+
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
17+
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
18+
* with IDs within this list are ignored when testing for existance of the value.
19+
*/
20+
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );
21+
22+
};

‎src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ SET(QGIS_CORE_SRCS
230230
qgsvectorlayerlabelprovider.cpp
231231
qgsvectorlayerrenderer.cpp
232232
qgsvectorlayerundocommand.cpp
233+
qgsvectorlayerutils.cpp
233234
qgsvectorsimplifymethod.cpp
234235
qgsvirtuallayerdefinition.cpp
235236
qgsvirtuallayerdefinitionutils.cpp
@@ -722,6 +723,7 @@ SET(QGIS_CORE_HDRS
722723
qgsvectorlayerlabelprovider.h
723724
qgsvectorlayerrenderer.h
724725
qgsvectorlayerundocommand.h
726+
qgsvectorlayerutils.h
725727
qgsvectorsimplifymethod.h
726728
qgsmapthemecollection.h
727729
qgsxmlutils.h

‎src/core/qgsvectorlayer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@ struct CORE_EXPORT QgsVectorJoinInfo
403403
* Provider to display vector data in a GRASS GIS layer.
404404
*
405405
* TODO QGIS3: Remove virtual from non-inherited methods (like isModified)
406+
* @see QgsVectorLayerUtils()
406407
*/
407408

408409

‎src/core/qgsvectorlayerutils.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/***************************************************************************
2+
qgsvectorlayerutils.cpp
3+
-----------------------
4+
Date : October 2016
5+
Copyright : (C) 2016 by Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsvectorlayerutils.h"
17+
18+
bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds )
19+
{
20+
if ( !layer )
21+
return false;
22+
23+
if ( fieldIndex < 0 || fieldIndex >= layer->fields().count() )
24+
return false;
25+
26+
QString fieldName = layer->fields().at( fieldIndex ).name();
27+
28+
// build up an optimised feature request
29+
QgsFeatureRequest request;
30+
request.setSubsetOfAttributes( QgsAttributeList() );
31+
request.setFlags( QgsFeatureRequest::NoGeometry );
32+
33+
// at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
34+
int limit = ignoreIds.size() + 1;
35+
request.setLimit( limit );
36+
37+
request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
38+
QgsExpression::quotedValue( value ) ) );
39+
40+
QgsFeature feat;
41+
QgsFeatureIterator it = layer->getFeatures( request );
42+
while ( it.nextFeature( feat ) )
43+
{
44+
if ( ignoreIds.contains( feat.id() ) )
45+
continue;
46+
47+
return true;
48+
}
49+
50+
return false;
51+
}

‎src/core/qgsvectorlayerutils.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/***************************************************************************
2+
qgsvectorlayerutils.h
3+
---------------------
4+
Date : October 2016
5+
Copyright : (C) 2016 by Nyall Dawson
6+
Email : nyall dot dawson at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSVECTORLAYERUTILS_H
17+
#define QGSVECTORLAYERUTILS_H
18+
19+
#include "qgsvectorlayer.h"
20+
21+
/** \ingroup core
22+
* \class QgsVectorLayerUtils
23+
* \brief Contains utility methods for working with QgsVectorLayers.
24+
*
25+
* \note Added in version 3.0
26+
*/
27+
28+
class CORE_EXPORT QgsVectorLayerUtils
29+
{
30+
public:
31+
32+
/**
33+
* Returns true if the specified value already exists within a field. This method can be used to test for uniqueness
34+
* of values inside a layer's attributes. An optional list of ignored feature IDs can be provided, if so, any features
35+
* with IDs within this list are ignored when testing for existance of the value.
36+
*/
37+
static bool valueExists( const QgsVectorLayer* layer, int fieldIndex, const QVariant& value, const QgsFeatureIds& ignoreIds = QgsFeatureIds() );
38+
39+
};
40+
41+
#endif // QGSVECTORLAYERUTILS_H

‎tests/src/python/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ ADD_PYTHON_TEST(PyQgsVectorColorRamp test_qgsvectorcolorramp.py)
111111
ADD_PYTHON_TEST(PyQgsVectorFileWriter test_qgsvectorfilewriter.py)
112112
ADD_PYTHON_TEST(PyQgsVectorLayer test_qgsvectorlayer.py)
113113
ADD_PYTHON_TEST(PyQgsVectorLayerEditBuffer test_qgsvectorlayereditbuffer.py)
114+
ADD_PYTHON_TEST(PyQgsVectorLayerUtils test_qgsvectorlayerutils.py)
114115
ADD_PYTHON_TEST(PyQgsZonalStatistics test_qgszonalstatistics.py)
115116
ADD_PYTHON_TEST(PyQgsMapLayerRegistry test_qgsmaplayerregistry.py)
116117
ADD_PYTHON_TEST(PyQgsVirtualLayerProvider test_provider_virtual.py)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# -*- coding: utf-8 -*-
2+
"""QGIS Unit tests for QgsVectorLayerUtils.
3+
4+
.. note:: This program is free software; you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation; either version 2 of the License, or
7+
(at your option) any later version.
8+
"""
9+
__author__ = 'Nyall Dawson'
10+
__date__ = '25/10/2016'
11+
__copyright__ = 'Copyright 2016, The QGIS Project'
12+
# This will get replaced with a git SHA1 when you do a git archive
13+
__revision__ = '$Format:%H$'
14+
15+
import qgis # NOQA
16+
17+
import os
18+
19+
from qgis.PyQt.QtCore import QVariant
20+
21+
from qgis.core import (QgsVectorLayer,
22+
QgsVectorLayerUtils,
23+
QgsField,
24+
QgsFields,
25+
QgsFeature
26+
)
27+
from qgis.testing import start_app, unittest
28+
from utilities import unitTestDataPath
29+
start_app()
30+
31+
32+
def createLayerWithOnePoint():
33+
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
34+
"addfeat", "memory")
35+
pr = layer.dataProvider()
36+
f = QgsFeature()
37+
f.setAttributes(["test", 123])
38+
assert pr.addFeatures([f])
39+
assert layer.pendingFeatureCount() == 1
40+
return layer
41+
42+
43+
class TestQgsVectorLayerUtils(unittest.TestCase):
44+
45+
def test_value_exists(self):
46+
layer = createLayerWithOnePoint()
47+
# add some more features
48+
f1 = QgsFeature(2)
49+
f1.setAttributes(["test1", 124])
50+
f2 = QgsFeature(3)
51+
f2.setAttributes(["test2", 125])
52+
f3 = QgsFeature(4)
53+
f3.setAttributes(["test3", 126])
54+
f4 = QgsFeature(5)
55+
f4.setAttributes(["test4", 127])
56+
layer.dataProvider().addFeatures([f1, f2, f3, f4])
57+
58+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test'))
59+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1'))
60+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test4'))
61+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'not present!'))
62+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 123))
63+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 124))
64+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 127))
65+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 99))
66+
67+
# no layer
68+
self.assertFalse(QgsVectorLayerUtils.valueExists(None, 1, 123))
69+
# bad field indexes
70+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, -1, 'test'))
71+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 100, 'test'))
72+
73+
# with ignore list
74+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5]))
75+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [999999]))
76+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [2]))
77+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [99999, 2]))
78+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 0, 'test1', [3, 4, 5, 2]))
79+
80+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [2, 4, 5]))
81+
self.assertTrue(QgsVectorLayerUtils.valueExists(layer, 1, 125, [999999]))
82+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [3]))
83+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [99999, 3]))
84+
self.assertFalse(QgsVectorLayerUtils.valueExists(layer, 1, 125, [2, 4, 5, 3]))
85+
86+
87+
if __name__ == '__main__':
88+
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.