Skip to content

Commit 3388857

Browse files
committed
Move uniqueValues to QgsFeatureSource
Also change signature of QgsVectorLayer/QgsVectorDataProvider uniqueValues method to match (and improve API)
1 parent f69d1c2 commit 3388857

30 files changed

+195
-111
lines changed

doc/api_break.dox

+2
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,7 @@ clause fragment which must be evaluated by the provider in order to calculate th
22752275
QGIS 3.0 defaultValue() only returns literal, constant defaultValues. A new method defaultValueClause
22762276
has been added which returns the SQL clause fragments which must be evaluated by the provider itself.
22772277
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
2278+
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
22782279

22792280

22802281
QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
@@ -2335,6 +2336,7 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
23352336
- addFeatures() no longer accepts a makeSelected boolean, and will not automatically select newly added features. If desired, features must be manually selected by calling selectByIds() after addFeatures()
23362337
- annotationForm() and setAnnotationForm() have been removed. Form path is stored in individual QgsFormAnnotation objects.
23372338
- setLayerTransparency, layerTransparency, and layerTransparencyChanged were removed. Use opacity, setOpacity and opacityChanged instead.
2339+
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
23382340

23392341

23402342
QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}

python/core/qgsfeaturesource.sip

+9
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,15 @@ class QgsFeatureSource
6969
:rtype: long
7070
%End
7171

72+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
73+
%Docstring
74+
Returns the set of unique values contained within the specified ``fieldIndex`` from this source.
75+
If specified, the ``limit`` option can be used to limit the number of returned values.
76+
The base class implementation uses a non-optimised approach of looping through
77+
all features in the source.
78+
:rtype: set of QVariant
79+
%End
80+
7281
};
7382

7483

python/core/qgsvectordataprovider.sip

-10
Original file line numberDiff line numberDiff line change
@@ -156,16 +156,6 @@ Bitmask of all provider's editing capabilities
156156
:rtype: QVariant
157157
%End
158158

159-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
160-
%Docstring
161-
Return unique values of an attribute
162-
\param index the index of the attribute
163-
\param uniqueValues values reference to the list to fill
164-
\param limit maxmum number of the values to return
165-
166-
Default implementation simply iterates the features
167-
%End
168-
169159
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
170160
QgsFeedback *feedback = 0 ) const;
171161
%Docstring

python/core/qgsvectorlayer.sip

+4-3
Original file line numberDiff line numberDiff line change
@@ -1507,18 +1507,19 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
15071507
:rtype: QgsEditorWidgetSetup
15081508
%End
15091509

1510-
void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
1510+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
1511+
15111512
%Docstring
15121513
Calculates a list of unique values contained within an attribute in the layer. Note that
15131514
in some circumstances when unsaved changes are present for the layer then the returned list
15141515
may contain outdated values (for instance when the attribute value in a saved feature has
15151516
been changed inside the edit buffer then the previous saved value will be included in the
15161517
returned list).
1517-
\param index column index for attribute
1518-
\param uniqueValues out: result list
1518+
\param fieldIndex column index for attribute
15191519
\param limit maximum number of values to return (or -1 if unlimited)
15201520
.. seealso:: minimumValue()
15211521
.. seealso:: maximumValue()
1522+
:rtype: set of QVariant
15221523
%End
15231524

15241525
QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,

src/core/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ SET(QGIS_CORE_SRCS
158158
qgsfeatureiterator.cpp
159159
qgsfeaturerequest.cpp
160160
qgsfeaturesink.cpp
161+
qgsfeaturesource.cpp
161162
qgsfeaturestore.cpp
162163
qgsfield.cpp
163164
qgsfieldconstraints.cpp

src/core/dxf/qgsdxfexport.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,7 @@ void QgsDxfExport::writeTables()
787787
}
788788
else
789789
{
790-
QList<QVariant> values;
791-
vl->uniqueValues( attrIdx, values );
790+
QSet<QVariant> values = vl->uniqueValues( attrIdx );
792791
Q_FOREACH ( const QVariant &v, values )
793792
{
794793
layerNames << dxfLayerName( v.toString() );

src/core/processing/qgsprocessingutils.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,8 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
274274
if ( !useSelection )
275275
{
276276
// not using selection, so use provider optimised version
277-
QList<QVariant> values;
278-
layer->uniqueValues( fieldIndex, values );
279-
return values;
277+
QSet<QVariant> values = layer->uniqueValues( fieldIndex );
278+
return values.toList();
280279
}
281280
else
282281
{

src/core/qgis.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ template<class Object> inline QgsSignalBlocker<Object> whileBlocking( Object *ob
173173
}
174174

175175
//! Hash for QVariant
176-
uint qHash( const QVariant &variant );
176+
CORE_EXPORT uint qHash( const QVariant &variant );
177177

178178
//! Returns a string representation of a double
179179
//! \param a double value

src/core/qgsfeaturesource.cpp

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/***************************************************************************
2+
qgsfeaturesource.cpp
3+
-------------------
4+
begin : May 2017
5+
copyright : (C) 2017 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsfeaturesource.h"
19+
#include "qgsfeaturerequest.h"
20+
#include "qgsfeatureiterator.h"
21+
22+
QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
23+
{
24+
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
25+
return QSet<QVariant>();
26+
27+
QgsFeatureRequest req;
28+
req.setFlags( QgsFeatureRequest::NoGeometry );
29+
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
30+
31+
QSet<QVariant> values;
32+
QgsFeatureIterator it = getFeatures( req );
33+
QgsFeature f;
34+
while ( it.nextFeature( f ) )
35+
{
36+
values.insert( f.attribute( fieldIndex ) );
37+
if ( limit > 0 && values.size() >= limit )
38+
return values;
39+
}
40+
return values;
41+
}
42+

src/core/qgsfeaturesource.h

100755100644
+9-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
#include "qgis_core.h"
2222
#include "qgis.h"
23+
#include "qgsfeaturerequest.h"
2324

2425
class QgsFeatureIterator;
25-
class QgsFeatureRequest;
2626
class QgsCoordinateReferenceSystem;
2727
class QgsFields;
2828

@@ -79,6 +79,14 @@ class CORE_EXPORT QgsFeatureSource
7979
*/
8080
virtual long featureCount() const = 0;
8181

82+
/**
83+
* Returns the set of unique values contained within the specified \a fieldIndex from this source.
84+
* If specified, the \a limit option can be used to limit the number of returned values.
85+
* The base class implementation uses a non-optimised approach of looping through
86+
* all features in the source.
87+
*/
88+
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
89+
8290
};
8391

8492
Q_DECLARE_METATYPE( QgsFeatureSource * )

src/core/qgsvectordataprovider.cpp

-22
Original file line numberDiff line numberDiff line change
@@ -433,28 +433,6 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
433433
return mCacheMaxValues[index];
434434
}
435435

436-
void QgsVectorDataProvider::uniqueValues( int index, QList<QVariant> &values, int limit ) const
437-
{
438-
QgsFeature f;
439-
QgsAttributeList keys;
440-
keys.append( index );
441-
QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ).setFlags( QgsFeatureRequest::NoGeometry ) );
442-
443-
QSet<QString> set;
444-
values.clear();
445-
446-
while ( fi.nextFeature( f ) )
447-
{
448-
if ( !set.contains( f.attribute( index ).toString() ) )
449-
{
450-
values.append( f.attribute( index ) );
451-
set.insert( f.attribute( index ).toString() );
452-
}
453-
454-
if ( limit >= 0 && values.size() >= limit )
455-
break;
456-
}
457-
}
458436

459437
QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
460438
{

src/core/qgsvectordataprovider.h

-10
Original file line numberDiff line numberDiff line change
@@ -186,16 +186,6 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
186186
*/
187187
virtual QVariant maximumValue( int index ) const;
188188

189-
/**
190-
* Return unique values of an attribute
191-
* \param index the index of the attribute
192-
* \param uniqueValues values reference to the list to fill
193-
* \param limit maxmum number of the values to return
194-
*
195-
* Default implementation simply iterates the features
196-
*/
197-
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
198-
199189
/**
200190
* Returns unique string values of an attribute which contain a specified subset string. Subset
201191
* matching is done in a case-insensitive manner.

src/core/qgsvectorlayer.cpp

+10-10
Original file line numberDiff line numberDiff line change
@@ -3010,23 +3010,23 @@ QString QgsVectorLayer::defaultValueExpression( int index ) const
30103010
return mFields.at( index ).defaultValueExpression();
30113011
}
30123012

3013-
void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
3013+
QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
30143014
{
3015-
uniqueValues.clear();
3015+
QSet<QVariant> uniqueValues;
30163016
if ( !mDataProvider )
30173017
{
3018-
return;
3018+
return uniqueValues;
30193019
}
30203020

30213021
QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
30223022
switch ( origin )
30233023
{
30243024
case QgsFields::OriginUnknown:
3025-
return;
3025+
return uniqueValues;
30263026

30273027
case QgsFields::OriginProvider: //a provider field
30283028
{
3029-
mDataProvider->uniqueValues( index, uniqueValues, limit );
3029+
uniqueValues = mDataProvider->uniqueValues( index, limit );
30303030

30313031
if ( mEditBuffer )
30323032
{
@@ -3070,7 +3070,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
30703070
}
30713071
}
30723072

3073-
return;
3073+
return uniqueValues;
30743074
}
30753075

30763076
case QgsFields::OriginEdit:
@@ -3080,8 +3080,8 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
30803080
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
30813081
mEditBuffer->mChangedAttributeValues.isEmpty() )
30823082
{
3083-
mDataProvider->uniqueValues( index, uniqueValues, limit );
3084-
return;
3083+
uniqueValues = mDataProvider->uniqueValues( index, limit );
3084+
return uniqueValues;
30853085
}
30863086
FALLTHROUGH;
30873087
//we need to go through each feature
@@ -3108,12 +3108,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
31083108
}
31093109
}
31103110

3111-
uniqueValues = val.values();
3112-
return;
3111+
return val.values().toSet();
31133112
}
31143113
}
31153114

31163115
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
3116+
return uniqueValues;
31173117
}
31183118

31193119
QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const

src/core/qgsvectorlayer.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -1423,13 +1423,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
14231423
* may contain outdated values (for instance when the attribute value in a saved feature has
14241424
* been changed inside the edit buffer then the previous saved value will be included in the
14251425
* returned list).
1426-
* \param index column index for attribute
1427-
* \param uniqueValues out: result list
1426+
* \param fieldIndex column index for attribute
14281427
* \param limit maximum number of values to return (or -1 if unlimited)
14291428
* \see minimumValue()
14301429
* \see maximumValue()
14311430
*/
1432-
void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
1431+
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;
14331432

14341433
/**
14351434
* Returns unique string values of an attribute which contain a specified subset string. Subset

src/gui/editorwidgets/qgsrelationreferencewidget.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -466,13 +466,12 @@ void QgsRelationReferenceWidget::init()
466466
{
467467
Q_FOREACH ( const QString &fieldName, mFilterFields )
468468
{
469-
QVariantList uniqueValues;
470469
int idx = mReferencedLayer->fields().lookupField( fieldName );
471470
QComboBox *cb = new QComboBox();
472471
cb->setProperty( "Field", fieldName );
473472
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
474473
mFilterComboBoxes << cb;
475-
mReferencedLayer->uniqueValues( idx, uniqueValues );
474+
QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
476475
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
477476
QVariant nullValue = QgsApplication::nullRepresentation();
478477
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );

src/gui/editorwidgets/qgsuniquevaluewidgetwrapper.cpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ void QgsUniqueValuesWidgetWrapper::initWidget( QWidget *editor )
6161

6262
QStringList sValues;
6363

64-
QList<QVariant> values;
65-
66-
layer()->uniqueValues( fieldIdx(), values );
64+
QSet< QVariant> values = layer()->uniqueValues( fieldIdx() );
6765

6866
Q_FOREACH ( const QVariant &v, values )
6967
{

src/gui/qgsexpressionbuilderwidget.cpp

+1-2
Original file line numberDiff line numberDiff line change
@@ -336,9 +336,8 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
336336
if ( fieldIndex < 0 )
337337
return;
338338

339-
QList<QVariant> values;
340339
QStringList strValues;
341-
mLayer->uniqueValues( fieldIndex, values, countLimit );
340+
QSet<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit );
342341
Q_FOREACH ( const QVariant &value, values )
343342
{
344343
QString strValue;

src/gui/qgsquerybuilder.cpp

+8-10
Original file line numberDiff line numberDiff line change
@@ -117,29 +117,27 @@ void QgsQueryBuilder::fillValues( int idx, int limit )
117117
mModelValues->clear();
118118

119119
// determine the field type
120-
QList<QVariant> values;
121-
mLayer->uniqueValues( idx, values, limit );
120+
QSet<QVariant> values = mLayer->uniqueValues( idx, limit );
122121

123-
QgsSettings settings;
124122
QString nullValue = QgsApplication::nullRepresentation();
125123

126124
QgsDebugMsg( QString( "nullValue: %1" ).arg( nullValue ) );
127125

128-
for ( int i = 0; i < values.size(); i++ )
126+
Q_FOREACH ( const QVariant &var, values )
129127
{
130128
QString value;
131-
if ( values[i].isNull() )
129+
if ( var.isNull() )
132130
value = nullValue;
133-
else if ( values[i].type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
134-
value = values[i].toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
131+
else if ( var.type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
132+
value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
135133
else
136-
value = values[i].toString();
134+
value = var.toString();
137135

138136
QStandardItem *myItem = new QStandardItem( value );
139137
myItem->setEditable( false );
140-
myItem->setData( values[i], Qt::UserRole + 1 );
138+
myItem->setData( var, Qt::UserRole + 1 );
141139
mModelValues->insertRow( mModelValues->rowCount(), myItem );
142-
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( values[i].isNull() ).arg( values[i].isNull() ? nullValue : values[i].toString() ) );
140+
QgsDebugMsg( QString( "Value is null: %1\nvalue: %2" ).arg( var.isNull() ).arg( var.isNull() ? nullValue : var.toString() ) );
143141
}
144142
}
145143

src/gui/symbology-ng/qgscategorizedsymbolrendererwidget.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -649,7 +649,7 @@ void QgsCategorizedSymbolRendererWidget::addCategories()
649649
}
650650
else
651651
{
652-
mLayer->uniqueValues( idx, unique_vals );
652+
unique_vals = mLayer->uniqueValues( idx ).toList();
653653
}
654654

655655
// ask to abort if too many classes

0 commit comments

Comments
 (0)