Skip to content
Permalink
Browse files

Move uniqueValues to QgsFeatureSource

Also change signature of QgsVectorLayer/QgsVectorDataProvider
uniqueValues method to match (and improve API)
  • Loading branch information
nyalldawson committed Jun 5, 2017
1 parent f69d1c2 commit 3388857526fb59cb30afdd5b7b2d36aa217351b3
@@ -2275,6 +2275,7 @@ clause fragment which must be evaluated by the provider in order to calculate th
QGIS 3.0 defaultValue() only returns literal, constant defaultValues. A new method defaultValueClause
has been added which returns the SQL clause fragments which must be evaluated by the provider itself.
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)


QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
@@ -2335,6 +2336,7 @@ displayExpression instead. For the map tip use mapTipTemplate() instead.
- 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()
- annotationForm() and setAnnotationForm() have been removed. Form path is stored in individual QgsFormAnnotation objects.
- setLayerTransparency, layerTransparency, and layerTransparencyChanged were removed. Use opacity, setOpacity and opacityChanged instead.
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)


QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}
@@ -69,6 +69,15 @@ class QgsFeatureSource
:rtype: long
%End

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

};


@@ -156,16 +156,6 @@ Bitmask of all provider's editing capabilities
:rtype: QVariant
%End

virtual void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
%Docstring
Return unique values of an attribute
\param index the index of the attribute
\param uniqueValues values reference to the list to fill
\param limit maxmum number of the values to return

Default implementation simply iterates the features
%End

virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
QgsFeedback *feedback = 0 ) const;
%Docstring
@@ -1507,18 +1507,19 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
:rtype: QgsEditorWidgetSetup
%End

void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;

%Docstring
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
been changed inside the edit buffer then the previous saved value will be included in the
returned list).
\param index column index for attribute
\param uniqueValues out: result list
\param fieldIndex column index for attribute
\param limit maximum number of values to return (or -1 if unlimited)
.. seealso:: minimumValue()
.. seealso:: maximumValue()
:rtype: set of QVariant
%End

QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
@@ -158,6 +158,7 @@ SET(QGIS_CORE_SRCS
qgsfeatureiterator.cpp
qgsfeaturerequest.cpp
qgsfeaturesink.cpp
qgsfeaturesource.cpp
qgsfeaturestore.cpp
qgsfield.cpp
qgsfieldconstraints.cpp
@@ -787,8 +787,7 @@ void QgsDxfExport::writeTables()
}
else
{
QList<QVariant> values;
vl->uniqueValues( attrIdx, values );
QSet<QVariant> values = vl->uniqueValues( attrIdx );
Q_FOREACH ( const QVariant &v, values )
{
layerNames << dxfLayerName( v.toString() );
@@ -274,9 +274,8 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
if ( !useSelection )
{
// not using selection, so use provider optimised version
QList<QVariant> values;
layer->uniqueValues( fieldIndex, values );
return values;
QSet<QVariant> values = layer->uniqueValues( fieldIndex );
return values.toList();
}
else
{
@@ -173,7 +173,7 @@ template<class Object> inline QgsSignalBlocker<Object> whileBlocking( Object *ob
}

//! Hash for QVariant
uint qHash( const QVariant &variant );
CORE_EXPORT uint qHash( const QVariant &variant );

//! Returns a string representation of a double
//! \param a double value
@@ -0,0 +1,42 @@
/***************************************************************************
qgsfeaturesource.cpp
-------------------
begin : May 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsfeaturesource.h"
#include "qgsfeaturerequest.h"
#include "qgsfeatureiterator.h"

QSet<QVariant> QgsFeatureSource::uniqueValues( int fieldIndex, int limit ) const
{
if ( fieldIndex < 0 || fieldIndex >= fields().count() )
return QSet<QVariant>();

QgsFeatureRequest req;
req.setFlags( QgsFeatureRequest::NoGeometry );
req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );

QSet<QVariant> values;
QgsFeatureIterator it = getFeatures( req );
QgsFeature f;
while ( it.nextFeature( f ) )
{
values.insert( f.attribute( fieldIndex ) );
if ( limit > 0 && values.size() >= limit )
return values;
}
return values;
}

10 src/core/qgsfeaturesource.h 100755 → 100644
@@ -20,9 +20,9 @@

#include "qgis_core.h"
#include "qgis.h"
#include "qgsfeaturerequest.h"

class QgsFeatureIterator;
class QgsFeatureRequest;
class QgsCoordinateReferenceSystem;
class QgsFields;

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

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

};

Q_DECLARE_METATYPE( QgsFeatureSource * )
@@ -433,28 +433,6 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
return mCacheMaxValues[index];
}

void QgsVectorDataProvider::uniqueValues( int index, QList<QVariant> &values, int limit ) const
{
QgsFeature f;
QgsAttributeList keys;
keys.append( index );
QgsFeatureIterator fi = getFeatures( QgsFeatureRequest().setSubsetOfAttributes( keys ).setFlags( QgsFeatureRequest::NoGeometry ) );

QSet<QString> set;
values.clear();

while ( fi.nextFeature( f ) )
{
if ( !set.contains( f.attribute( index ).toString() ) )
{
values.append( f.attribute( index ) );
set.insert( f.attribute( index ).toString() );
}

if ( limit >= 0 && values.size() >= limit )
break;
}
}

QStringList QgsVectorDataProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
{
@@ -186,16 +186,6 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider, public QgsFeat
*/
virtual QVariant maximumValue( int index ) const;

/**
* Return unique values of an attribute
* \param index the index of the attribute
* \param uniqueValues values reference to the list to fill
* \param limit maxmum number of the values to return
*
* Default implementation simply iterates the features
*/
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;

/**
* Returns unique string values of an attribute which contain a specified subset string. Subset
* matching is done in a case-insensitive manner.
@@ -3010,23 +3010,23 @@ QString QgsVectorLayer::defaultValueExpression( int index ) const
return mFields.at( index ).defaultValueExpression();
}

void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
QSet<QVariant> QgsVectorLayer::uniqueValues( int index, int limit ) const
{
uniqueValues.clear();
QSet<QVariant> uniqueValues;
if ( !mDataProvider )
{
return;
return uniqueValues;
}

QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
switch ( origin )
{
case QgsFields::OriginUnknown:
return;
return uniqueValues;

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

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

return;
return uniqueValues;
}

case QgsFields::OriginEdit:
@@ -3080,8 +3080,8 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
mEditBuffer->mChangedAttributeValues.isEmpty() )
{
mDataProvider->uniqueValues( index, uniqueValues, limit );
return;
uniqueValues = mDataProvider->uniqueValues( index, limit );
return uniqueValues;
}
FALLTHROUGH;
//we need to go through each feature
@@ -3108,12 +3108,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
}
}

uniqueValues = val.values();
return;
return val.values().toSet();
}
}

Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
return uniqueValues;
}

QStringList QgsVectorLayer::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
@@ -1423,13 +1423,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* may contain outdated values (for instance when the attribute value in a saved feature has
* been changed inside the edit buffer then the previous saved value will be included in the
* returned list).
* \param index column index for attribute
* \param uniqueValues out: result list
* \param fieldIndex column index for attribute
* \param limit maximum number of values to return (or -1 if unlimited)
* \see minimumValue()
* \see maximumValue()
*/
void uniqueValues( int index, QList<QVariant> &uniqueValues SIP_OUT, int limit = -1 ) const;
QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const override;

/**
* Returns unique string values of an attribute which contain a specified subset string. Subset
@@ -466,13 +466,12 @@ void QgsRelationReferenceWidget::init()
{
Q_FOREACH ( const QString &fieldName, mFilterFields )
{
QVariantList uniqueValues;
int idx = mReferencedLayer->fields().lookupField( fieldName );
QComboBox *cb = new QComboBox();
cb->setProperty( "Field", fieldName );
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
mFilterComboBoxes << cb;
mReferencedLayer->uniqueValues( idx, uniqueValues );
QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
QVariant nullValue = QgsApplication::nullRepresentation();
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );
@@ -61,9 +61,7 @@ void QgsUniqueValuesWidgetWrapper::initWidget( QWidget *editor )

QStringList sValues;

QList<QVariant> values;

layer()->uniqueValues( fieldIdx(), values );
QSet< QVariant> values = layer()->uniqueValues( fieldIdx() );

Q_FOREACH ( const QVariant &v, values )
{
@@ -336,9 +336,8 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
if ( fieldIndex < 0 )
return;

QList<QVariant> values;
QStringList strValues;
mLayer->uniqueValues( fieldIndex, values, countLimit );
QSet<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit );
Q_FOREACH ( const QVariant &value, values )
{
QString strValue;
@@ -117,29 +117,27 @@ void QgsQueryBuilder::fillValues( int idx, int limit )
mModelValues->clear();

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

QgsSettings settings;
QString nullValue = QgsApplication::nullRepresentation();

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

for ( int i = 0; i < values.size(); i++ )
Q_FOREACH ( const QVariant &var, values )
{
QString value;
if ( values[i].isNull() )
if ( var.isNull() )
value = nullValue;
else if ( values[i].type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
value = values[i].toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
else if ( var.type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
else
value = values[i].toString();
value = var.toString();

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

@@ -649,7 +649,7 @@ void QgsCategorizedSymbolRendererWidget::addCategories()
}
else
{
mLayer->uniqueValues( idx, unique_vals );
unique_vals = mLayer->uniqueValues( idx ).toList();
}

// ask to abort if too many classes

0 comments on commit 3388857

Please sign in to comment.
You can’t perform that action at this time.