mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
Move uniqueValues to QgsFeatureSource
Also change signature of QgsVectorLayer/QgsVectorDataProvider uniqueValues method to match (and improve API)
This commit is contained in:
parent
f69d1c2065
commit
3388857526
@ -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
|
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.
|
has been added which returns the SQL clause fragments which must be evaluated by the provider itself.
|
||||||
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
|
- isSaveAndLoadStyleToDBSupported() was renamed to isSaveAndLoadStyleToDatabaseSupported()
|
||||||
|
- The c++ signature for uniqueValues() has changed (the PyQGIS method remains unchanged)
|
||||||
|
|
||||||
|
|
||||||
QgsVectorJoinInfo {#qgis_api_break_3_0_QgsVectorJoinInfo}
|
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()
|
- 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.
|
- 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.
|
- 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}
|
QgsVectorLayerEditBuffer {#qgis_api_break_3_0_QgsVectorLayerEditBuffer}
|
||||||
|
@ -69,6 +69,15 @@ class QgsFeatureSource
|
|||||||
:rtype: long
|
:rtype: long
|
||||||
%End
|
%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
|
:rtype: QVariant
|
||||||
%End
|
%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,
|
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
||||||
QgsFeedback *feedback = 0 ) const;
|
QgsFeedback *feedback = 0 ) const;
|
||||||
%Docstring
|
%Docstring
|
||||||
|
@ -1507,18 +1507,19 @@ Assembles mUpdatedFields considering provider fields, joined fields and added fi
|
|||||||
:rtype: QgsEditorWidgetSetup
|
:rtype: QgsEditorWidgetSetup
|
||||||
%End
|
%End
|
||||||
|
|
||||||
void uniqueValues( int index, QList<QVariant> &uniqueValues /Out/, int limit = -1 ) const;
|
virtual QSet<QVariant> uniqueValues( int fieldIndex, int limit = -1 ) const;
|
||||||
|
|
||||||
%Docstring
|
%Docstring
|
||||||
Calculates a list of unique values contained within an attribute in the layer. Note that
|
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
|
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
|
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
|
been changed inside the edit buffer then the previous saved value will be included in the
|
||||||
returned list).
|
returned list).
|
||||||
\param index column index for attribute
|
\param fieldIndex column index for attribute
|
||||||
\param uniqueValues out: result list
|
|
||||||
\param limit maximum number of values to return (or -1 if unlimited)
|
\param limit maximum number of values to return (or -1 if unlimited)
|
||||||
.. seealso:: minimumValue()
|
.. seealso:: minimumValue()
|
||||||
.. seealso:: maximumValue()
|
.. seealso:: maximumValue()
|
||||||
|
:rtype: set of QVariant
|
||||||
%End
|
%End
|
||||||
|
|
||||||
QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
||||||
|
@ -158,6 +158,7 @@ SET(QGIS_CORE_SRCS
|
|||||||
qgsfeatureiterator.cpp
|
qgsfeatureiterator.cpp
|
||||||
qgsfeaturerequest.cpp
|
qgsfeaturerequest.cpp
|
||||||
qgsfeaturesink.cpp
|
qgsfeaturesink.cpp
|
||||||
|
qgsfeaturesource.cpp
|
||||||
qgsfeaturestore.cpp
|
qgsfeaturestore.cpp
|
||||||
qgsfield.cpp
|
qgsfield.cpp
|
||||||
qgsfieldconstraints.cpp
|
qgsfieldconstraints.cpp
|
||||||
|
@ -787,8 +787,7 @@ void QgsDxfExport::writeTables()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QList<QVariant> values;
|
QSet<QVariant> values = vl->uniqueValues( attrIdx );
|
||||||
vl->uniqueValues( attrIdx, values );
|
|
||||||
Q_FOREACH ( const QVariant &v, values )
|
Q_FOREACH ( const QVariant &v, values )
|
||||||
{
|
{
|
||||||
layerNames << dxfLayerName( v.toString() );
|
layerNames << dxfLayerName( v.toString() );
|
||||||
|
@ -274,9 +274,8 @@ QList<QVariant> QgsProcessingUtils::uniqueValues( QgsVectorLayer *layer, int fie
|
|||||||
if ( !useSelection )
|
if ( !useSelection )
|
||||||
{
|
{
|
||||||
// not using selection, so use provider optimised version
|
// not using selection, so use provider optimised version
|
||||||
QList<QVariant> values;
|
QSet<QVariant> values = layer->uniqueValues( fieldIndex );
|
||||||
layer->uniqueValues( fieldIndex, values );
|
return values.toList();
|
||||||
return values;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -173,7 +173,7 @@ template<class Object> inline QgsSignalBlocker<Object> whileBlocking( Object *ob
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Hash for QVariant
|
//! Hash for QVariant
|
||||||
uint qHash( const QVariant &variant );
|
CORE_EXPORT uint qHash( const QVariant &variant );
|
||||||
|
|
||||||
//! Returns a string representation of a double
|
//! Returns a string representation of a double
|
||||||
//! \param a double value
|
//! \param a double value
|
||||||
|
42
src/core/qgsfeaturesource.cpp
Normal file
42
src/core/qgsfeaturesource.cpp
Normal file
@ -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
Executable file → Normal file
10
src/core/qgsfeaturesource.h
Executable file → Normal file
@ -20,9 +20,9 @@
|
|||||||
|
|
||||||
#include "qgis_core.h"
|
#include "qgis_core.h"
|
||||||
#include "qgis.h"
|
#include "qgis.h"
|
||||||
|
#include "qgsfeaturerequest.h"
|
||||||
|
|
||||||
class QgsFeatureIterator;
|
class QgsFeatureIterator;
|
||||||
class QgsFeatureRequest;
|
|
||||||
class QgsCoordinateReferenceSystem;
|
class QgsCoordinateReferenceSystem;
|
||||||
class QgsFields;
|
class QgsFields;
|
||||||
|
|
||||||
@ -79,6 +79,14 @@ class CORE_EXPORT QgsFeatureSource
|
|||||||
*/
|
*/
|
||||||
virtual long featureCount() const = 0;
|
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 * )
|
Q_DECLARE_METATYPE( QgsFeatureSource * )
|
||||||
|
@ -433,28 +433,6 @@ QVariant QgsVectorDataProvider::maximumValue( int index ) const
|
|||||||
return mCacheMaxValues[index];
|
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
|
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;
|
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
|
* Returns unique string values of an attribute which contain a specified subset string. Subset
|
||||||
* matching is done in a case-insensitive manner.
|
* matching is done in a case-insensitive manner.
|
||||||
|
@ -3010,23 +3010,23 @@ QString QgsVectorLayer::defaultValueExpression( int index ) const
|
|||||||
return mFields.at( index ).defaultValueExpression();
|
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 )
|
if ( !mDataProvider )
|
||||||
{
|
{
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
|
QgsFields::FieldOrigin origin = mFields.fieldOrigin( index );
|
||||||
switch ( origin )
|
switch ( origin )
|
||||||
{
|
{
|
||||||
case QgsFields::OriginUnknown:
|
case QgsFields::OriginUnknown:
|
||||||
return;
|
return uniqueValues;
|
||||||
|
|
||||||
case QgsFields::OriginProvider: //a provider field
|
case QgsFields::OriginProvider: //a provider field
|
||||||
{
|
{
|
||||||
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
uniqueValues = mDataProvider->uniqueValues( index, limit );
|
||||||
|
|
||||||
if ( mEditBuffer )
|
if ( mEditBuffer )
|
||||||
{
|
{
|
||||||
@ -3070,7 +3070,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
case QgsFields::OriginEdit:
|
case QgsFields::OriginEdit:
|
||||||
@ -3080,8 +3080,8 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||||
{
|
{
|
||||||
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
uniqueValues = mDataProvider->uniqueValues( index, limit );
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
FALLTHROUGH;
|
FALLTHROUGH;
|
||||||
//we need to go through each feature
|
//we need to go through each feature
|
||||||
@ -3108,12 +3108,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uniqueValues = val.values();
|
return val.values().toSet();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
|
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
|
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
|
* 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
|
* been changed inside the edit buffer then the previous saved value will be included in the
|
||||||
* returned list).
|
* returned list).
|
||||||
* \param index column index for attribute
|
* \param fieldIndex column index for attribute
|
||||||
* \param uniqueValues out: result list
|
|
||||||
* \param limit maximum number of values to return (or -1 if unlimited)
|
* \param limit maximum number of values to return (or -1 if unlimited)
|
||||||
* \see minimumValue()
|
* \see minimumValue()
|
||||||
* \see maximumValue()
|
* \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
|
* 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 )
|
Q_FOREACH ( const QString &fieldName, mFilterFields )
|
||||||
{
|
{
|
||||||
QVariantList uniqueValues;
|
|
||||||
int idx = mReferencedLayer->fields().lookupField( fieldName );
|
int idx = mReferencedLayer->fields().lookupField( fieldName );
|
||||||
QComboBox *cb = new QComboBox();
|
QComboBox *cb = new QComboBox();
|
||||||
cb->setProperty( "Field", fieldName );
|
cb->setProperty( "Field", fieldName );
|
||||||
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
|
cb->setProperty( "FieldAlias", mReferencedLayer->attributeDisplayName( idx ) );
|
||||||
mFilterComboBoxes << cb;
|
mFilterComboBoxes << cb;
|
||||||
mReferencedLayer->uniqueValues( idx, uniqueValues );
|
QVariantList uniqueValues = mReferencedLayer->uniqueValues( idx ).toList();
|
||||||
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
|
cb->addItem( mReferencedLayer->attributeDisplayName( idx ) );
|
||||||
QVariant nullValue = QgsApplication::nullRepresentation();
|
QVariant nullValue = QgsApplication::nullRepresentation();
|
||||||
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );
|
cb->addItem( nullValue.toString(), QVariant( mReferencedLayer->fields().at( idx ).type() ) );
|
||||||
|
@ -61,9 +61,7 @@ void QgsUniqueValuesWidgetWrapper::initWidget( QWidget *editor )
|
|||||||
|
|
||||||
QStringList sValues;
|
QStringList sValues;
|
||||||
|
|
||||||
QList<QVariant> values;
|
QSet< QVariant> values = layer()->uniqueValues( fieldIdx() );
|
||||||
|
|
||||||
layer()->uniqueValues( fieldIdx(), values );
|
|
||||||
|
|
||||||
Q_FOREACH ( const QVariant &v, values )
|
Q_FOREACH ( const QVariant &v, values )
|
||||||
{
|
{
|
||||||
|
@ -336,9 +336,8 @@ void QgsExpressionBuilderWidget::fillFieldValues( const QString &fieldName, int
|
|||||||
if ( fieldIndex < 0 )
|
if ( fieldIndex < 0 )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QList<QVariant> values;
|
|
||||||
QStringList strValues;
|
QStringList strValues;
|
||||||
mLayer->uniqueValues( fieldIndex, values, countLimit );
|
QSet<QVariant> values = mLayer->uniqueValues( fieldIndex, countLimit );
|
||||||
Q_FOREACH ( const QVariant &value, values )
|
Q_FOREACH ( const QVariant &value, values )
|
||||||
{
|
{
|
||||||
QString strValue;
|
QString strValue;
|
||||||
|
@ -117,29 +117,27 @@ void QgsQueryBuilder::fillValues( int idx, int limit )
|
|||||||
mModelValues->clear();
|
mModelValues->clear();
|
||||||
|
|
||||||
// determine the field type
|
// determine the field type
|
||||||
QList<QVariant> values;
|
QSet<QVariant> values = mLayer->uniqueValues( idx, limit );
|
||||||
mLayer->uniqueValues( idx, values, limit );
|
|
||||||
|
|
||||||
QgsSettings settings;
|
|
||||||
QString nullValue = QgsApplication::nullRepresentation();
|
QString nullValue = QgsApplication::nullRepresentation();
|
||||||
|
|
||||||
QgsDebugMsg( QString( "nullValue: %1" ).arg( nullValue ) );
|
QgsDebugMsg( QString( "nullValue: %1" ).arg( nullValue ) );
|
||||||
|
|
||||||
for ( int i = 0; i < values.size(); i++ )
|
Q_FOREACH ( const QVariant &var, values )
|
||||||
{
|
{
|
||||||
QString value;
|
QString value;
|
||||||
if ( values[i].isNull() )
|
if ( var.isNull() )
|
||||||
value = nullValue;
|
value = nullValue;
|
||||||
else if ( values[i].type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
|
else if ( var.type() == QVariant::Date && mLayer->providerType() == QLatin1String( "ogr" ) && mLayer->storageType() == QLatin1String( "ESRI Shapefile" ) )
|
||||||
value = values[i].toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
|
value = var.toDate().toString( QStringLiteral( "yyyy/MM/dd" ) );
|
||||||
else
|
else
|
||||||
value = values[i].toString();
|
value = var.toString();
|
||||||
|
|
||||||
QStandardItem *myItem = new QStandardItem( value );
|
QStandardItem *myItem = new QStandardItem( value );
|
||||||
myItem->setEditable( false );
|
myItem->setEditable( false );
|
||||||
myItem->setData( values[i], Qt::UserRole + 1 );
|
myItem->setData( var, Qt::UserRole + 1 );
|
||||||
mModelValues->insertRow( mModelValues->rowCount(), myItem );
|
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
|
else
|
||||||
{
|
{
|
||||||
mLayer->uniqueValues( idx, unique_vals );
|
unique_vals = mLayer->uniqueValues( idx ).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ask to abort if too many classes
|
// ask to abort if too many classes
|
||||||
|
@ -607,9 +607,9 @@ QVariant QgsMssqlProvider::maximumValue( int index ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the list of unique values of an attribute
|
// Returns the list of unique values of an attribute
|
||||||
void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
|
QSet<QVariant> QgsMssqlProvider::uniqueValues( int index, int limit ) const
|
||||||
{
|
{
|
||||||
uniqueValues.clear();
|
QSet<QVariant> uniqueValues;
|
||||||
|
|
||||||
// get the field name
|
// get the field name
|
||||||
QgsField fld = mAttributeFields.at( index );
|
QgsField fld = mAttributeFields.at( index );
|
||||||
@ -643,9 +643,10 @@ void QgsMssqlProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, i
|
|||||||
// read all features
|
// read all features
|
||||||
while ( query.next() )
|
while ( query.next() )
|
||||||
{
|
{
|
||||||
uniqueValues.append( query.value( 0 ) );
|
uniqueValues.insert( query.value( 0 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,7 +66,7 @@ class QgsMssqlProvider : public QgsVectorDataProvider
|
|||||||
virtual QStringList subLayers() const override;
|
virtual QStringList subLayers() const override;
|
||||||
virtual QVariant minimumValue( int index ) const override;
|
virtual QVariant minimumValue( int index ) const override;
|
||||||
virtual QVariant maximumValue( int index ) const override;
|
virtual QVariant maximumValue( int index ) const override;
|
||||||
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
|
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
|
||||||
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
|
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request ) const override;
|
||||||
|
|
||||||
virtual QgsWkbTypes::Type wkbType() const override;
|
virtual QgsWkbTypes::Type wkbType() const override;
|
||||||
|
@ -30,6 +30,8 @@ email : sherman at mrcc.com
|
|||||||
#include "qgsgeometry.h"
|
#include "qgsgeometry.h"
|
||||||
#include "qgscoordinatereferencesystem.h"
|
#include "qgscoordinatereferencesystem.h"
|
||||||
#include "qgsvectorlayerexporter.h"
|
#include "qgsvectorlayerexporter.h"
|
||||||
|
#include "qgis.h"
|
||||||
|
|
||||||
|
|
||||||
#define CPL_SUPRESS_CPLUSPLUS //#spellok
|
#define CPL_SUPRESS_CPLUSPLUS //#spellok
|
||||||
#include <gdal.h> // to collect version information
|
#include <gdal.h> // to collect version information
|
||||||
@ -2949,17 +2951,17 @@ QgsCoordinateReferenceSystem QgsOgrProvider::crs() const
|
|||||||
return srs;
|
return srs;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
|
QSet<QVariant> QgsOgrProvider::uniqueValues( int index, int limit ) const
|
||||||
{
|
{
|
||||||
uniqueValues.clear();
|
QSet<QVariant> uniqueValues;
|
||||||
|
|
||||||
if ( !mValid || index < 0 || index >= mAttributeFields.count() )
|
if ( !mValid || index < 0 || index >= mAttributeFields.count() )
|
||||||
return;
|
return uniqueValues;
|
||||||
|
|
||||||
QgsField fld = mAttributeFields.at( index );
|
QgsField fld = mAttributeFields.at( index );
|
||||||
if ( fld.name().isNull() )
|
if ( fld.name().isNull() )
|
||||||
{
|
{
|
||||||
return; //not a provider field
|
return uniqueValues; //not a provider field
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray sql = "SELECT DISTINCT " + quotedIdentifier( textEncoding()->fromUnicode( fld.name() ) );
|
QByteArray sql = "SELECT DISTINCT " + quotedIdentifier( textEncoding()->fromUnicode( fld.name() ) );
|
||||||
@ -2977,7 +2979,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
if ( !l )
|
if ( !l )
|
||||||
{
|
{
|
||||||
QgsDebugMsg( "Failed to execute SQL" );
|
QgsDebugMsg( "Failed to execute SQL" );
|
||||||
return QgsVectorDataProvider::uniqueValues( index, uniqueValues, limit );
|
return QgsVectorDataProvider::uniqueValues( index, limit );
|
||||||
}
|
}
|
||||||
|
|
||||||
OGRFeatureH f;
|
OGRFeatureH f;
|
||||||
@ -2991,6 +2993,7 @@ void QgsOgrProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
}
|
}
|
||||||
|
|
||||||
OGR_DS_ReleaseResultSet( ogrDataSource, l );
|
OGR_DS_ReleaseResultSet( ogrDataSource, l );
|
||||||
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QgsOgrProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
QStringList QgsOgrProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
||||||
|
@ -103,7 +103,7 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
|||||||
bool isValid() const override;
|
bool isValid() const override;
|
||||||
QVariant minimumValue( int index ) const override;
|
QVariant minimumValue( int index ) const override;
|
||||||
QVariant maximumValue( int index ) const override;
|
QVariant maximumValue( int index ) const override;
|
||||||
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
|
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
|
||||||
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
||||||
QgsFeedback *feedback = nullptr ) const override;
|
QgsFeedback *feedback = nullptr ) const override;
|
||||||
|
|
||||||
|
@ -1553,9 +1553,9 @@ QVariant QgsPostgresProvider::minimumValue( int index ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the list of unique values of an attribute
|
// Returns the list of unique values of an attribute
|
||||||
void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues, int limit ) const
|
QSet<QVariant> QgsPostgresProvider::uniqueValues( int index, int limit ) const
|
||||||
{
|
{
|
||||||
uniqueValues.clear();
|
QSet<QVariant> uniqueValues;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1583,12 +1583,13 @@ void QgsPostgresProvider::uniqueValues( int index, QList<QVariant> &uniqueValues
|
|||||||
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
if ( res.PQresultStatus() == PGRES_TUPLES_OK )
|
||||||
{
|
{
|
||||||
for ( int i = 0; i < res.PQntuples(); i++ )
|
for ( int i = 0; i < res.PQntuples(); i++ )
|
||||||
uniqueValues.append( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
|
uniqueValues.insert( convertValue( fld.type(), fld.subType(), res.PQgetvalue( i, 0 ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch ( PGFieldNotFound )
|
catch ( PGFieldNotFound )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QgsPostgresProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
QStringList QgsPostgresProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
||||||
|
@ -126,7 +126,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
|
|||||||
QString dataComment() const override;
|
QString dataComment() const override;
|
||||||
QVariant minimumValue( int index ) const override;
|
QVariant minimumValue( int index ) const override;
|
||||||
QVariant maximumValue( int index ) const override;
|
QVariant maximumValue( int index ) const override;
|
||||||
virtual void uniqueValues( int index, QList<QVariant> &uniqueValues, int limit = -1 ) const override;
|
virtual QSet< QVariant > uniqueValues( int index, int limit = -1 ) const override;
|
||||||
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
||||||
QgsFeedback *feedback = nullptr ) const override;
|
QgsFeedback *feedback = nullptr ) const override;
|
||||||
virtual void enumValues( int index, QStringList &enumList ) const override;
|
virtual void enumValues( int index, QStringList &enumList ) const override;
|
||||||
|
@ -3641,17 +3641,17 @@ QVariant QgsSpatiaLiteProvider::maximumValue( int index ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns the list of unique values of an attribute
|
// Returns the list of unique values of an attribute
|
||||||
void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueValues, int limit ) const
|
QSet<QVariant> QgsSpatiaLiteProvider::uniqueValues( int index, int limit ) const
|
||||||
{
|
{
|
||||||
sqlite3_stmt *stmt = nullptr;
|
sqlite3_stmt *stmt = nullptr;
|
||||||
QString sql;
|
QString sql;
|
||||||
|
|
||||||
uniqueValues.clear();
|
QSet<QVariant> uniqueValues;
|
||||||
|
|
||||||
// get the field name
|
// get the field name
|
||||||
if ( index < 0 || index >= mAttributeFields.count() )
|
if ( index < 0 || index >= mAttributeFields.count() )
|
||||||
{
|
{
|
||||||
return; //invalid field
|
return uniqueValues; //invalid field
|
||||||
}
|
}
|
||||||
QgsField fld = mAttributeFields.at( index );
|
QgsField fld = mAttributeFields.at( index );
|
||||||
|
|
||||||
@ -3674,7 +3674,7 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
|
|||||||
{
|
{
|
||||||
// some error occurred
|
// some error occurred
|
||||||
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
|
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ( 1 )
|
while ( 1 )
|
||||||
@ -3694,16 +3694,16 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
|
|||||||
switch ( sqlite3_column_type( stmt, 0 ) )
|
switch ( sqlite3_column_type( stmt, 0 ) )
|
||||||
{
|
{
|
||||||
case SQLITE_INTEGER:
|
case SQLITE_INTEGER:
|
||||||
uniqueValues.append( QVariant( sqlite3_column_int( stmt, 0 ) ) );
|
uniqueValues.insert( QVariant( sqlite3_column_int( stmt, 0 ) ) );
|
||||||
break;
|
break;
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
uniqueValues.append( QVariant( sqlite3_column_double( stmt, 0 ) ) );
|
uniqueValues.insert( QVariant( sqlite3_column_double( stmt, 0 ) ) );
|
||||||
break;
|
break;
|
||||||
case SQLITE_TEXT:
|
case SQLITE_TEXT:
|
||||||
uniqueValues.append( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
|
uniqueValues.insert( QVariant( QString::fromUtf8( ( const char * ) sqlite3_column_text( stmt, 0 ) ) ) );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
uniqueValues.append( QVariant( mAttributeFields.at( index ).type() ) );
|
uniqueValues.insert( QVariant( mAttributeFields.at( index ).type() ) );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3711,13 +3711,13 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
|
|||||||
{
|
{
|
||||||
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
|
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, sqlite3_errmsg( mSqliteHandle ) ), tr( "SpatiaLite" ) );
|
||||||
sqlite3_finalize( stmt );
|
sqlite3_finalize( stmt );
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlite3_finalize( stmt );
|
sqlite3_finalize( stmt );
|
||||||
|
|
||||||
return;
|
return uniqueValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList QgsSpatiaLiteProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
QStringList QgsSpatiaLiteProvider::uniqueStringsMatching( int index, const QString &substring, int limit, QgsFeedback *feedback ) const
|
||||||
|
@ -96,7 +96,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
|
|||||||
QgsFields fields() const override;
|
QgsFields fields() const override;
|
||||||
QVariant minimumValue( int index ) const override;
|
QVariant minimumValue( int index ) const override;
|
||||||
QVariant maximumValue( int index ) const override;
|
QVariant maximumValue( int index ) const override;
|
||||||
virtual void uniqueValues( int index, QList < QVariant > &uniqueValues, int limit = -1 ) const override;
|
virtual QSet<QVariant> uniqueValues( int index, int limit = -1 ) const override;
|
||||||
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
virtual QStringList uniqueStringsMatching( int index, const QString &substring, int limit = -1,
|
||||||
QgsFeedback *feedback = nullptr ) const override;
|
QgsFeedback *feedback = nullptr ) const override;
|
||||||
|
|
||||||
|
@ -310,9 +310,8 @@ void TestQgsVectorLayer::uniqueValues()
|
|||||||
QgsVectorLayer *vLayer = static_cast< QgsVectorLayer * >( mpPointsLayer );
|
QgsVectorLayer *vLayer = static_cast< QgsVectorLayer * >( mpPointsLayer );
|
||||||
|
|
||||||
//test with invalid field
|
//test with invalid field
|
||||||
QList<QVariant> values;
|
QSet<QVariant> values = vLayer->uniqueValues( 1000 );
|
||||||
vLayer->uniqueValues( 1000, values );
|
QCOMPARE( values.count(), 0 );
|
||||||
QCOMPARE( values.length(), 0 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestQgsVectorLayer::minimumValue()
|
void TestQgsVectorLayer::minimumValue()
|
||||||
|
@ -51,6 +51,7 @@ ADD_PYTHON_TEST(PyQgsExpressionLineEdit test_qgsexpressionlineedit.py)
|
|||||||
ADD_PYTHON_TEST(PyQgsExtentGroupBox test_qgsextentgroupbox.py)
|
ADD_PYTHON_TEST(PyQgsExtentGroupBox test_qgsextentgroupbox.py)
|
||||||
ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
|
ADD_PYTHON_TEST(PyQgsFeature test_qgsfeature.py)
|
||||||
ADD_PYTHON_TEST(PyQgsFeatureSink test_qgsfeaturesink.py)
|
ADD_PYTHON_TEST(PyQgsFeatureSink test_qgsfeaturesink.py)
|
||||||
|
ADD_PYTHON_TEST(PyQgsFeatureSource test_qgsfeaturesource.py)
|
||||||
ADD_PYTHON_TEST(PyQgsFieldFormattersTest test_qgsfieldformatters.py)
|
ADD_PYTHON_TEST(PyQgsFieldFormattersTest test_qgsfieldformatters.py)
|
||||||
ADD_PYTHON_TEST(PyQgsFillSymbolLayers test_qgsfillsymbollayers.py)
|
ADD_PYTHON_TEST(PyQgsFillSymbolLayers test_qgsfillsymbollayers.py)
|
||||||
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
|
ADD_PYTHON_TEST(PyQgsProject test_qgsproject.py)
|
||||||
|
67
tests/src/python/test_qgsfeaturesource.py
Normal file
67
tests/src/python/test_qgsfeaturesource.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""QGIS Unit tests for QgsFeatureSource.
|
||||||
|
|
||||||
|
.. note:: 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.
|
||||||
|
"""
|
||||||
|
__author__ = '(C) 2017 by Nyall Dawson'
|
||||||
|
__date__ = '26/04/2017'
|
||||||
|
__copyright__ = 'Copyright 2017, The QGIS Project'
|
||||||
|
# This will get replaced with a git SHA1 when you do a git archive
|
||||||
|
__revision__ = '$Format:%H$'
|
||||||
|
import qgis # NOQA
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from qgis.core import (QgsVectorLayer,
|
||||||
|
QgsFeature,
|
||||||
|
QgsGeometry,
|
||||||
|
QgsPointXY)
|
||||||
|
from qgis.PyQt.QtCore import QVariant
|
||||||
|
from qgis.testing import start_app, unittest
|
||||||
|
start_app()
|
||||||
|
|
||||||
|
|
||||||
|
def createLayerWithFivePoints():
|
||||||
|
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
|
||||||
|
"addfeat", "memory")
|
||||||
|
pr = layer.dataProvider()
|
||||||
|
f = QgsFeature()
|
||||||
|
f.setAttributes(["test", 1])
|
||||||
|
f.setGeometry(QgsGeometry.fromPoint(QgsPointXY(100, 200)))
|
||||||
|
f2 = QgsFeature()
|
||||||
|
f2.setAttributes(["test2", 3])
|
||||||
|
f2.setGeometry(QgsGeometry.fromPoint(QgsPointXY(200, 200)))
|
||||||
|
f3 = QgsFeature()
|
||||||
|
f3.setAttributes(["test2", 3])
|
||||||
|
f3.setGeometry(QgsGeometry.fromPoint(QgsPointXY(300, 200)))
|
||||||
|
f4 = QgsFeature()
|
||||||
|
f4.setAttributes(["test3", 3])
|
||||||
|
f4.setGeometry(QgsGeometry.fromPoint(QgsPointXY(400, 300)))
|
||||||
|
f5 = QgsFeature()
|
||||||
|
f5.setAttributes(["test4", 4])
|
||||||
|
f5.setGeometry(QgsGeometry.fromPoint(QgsPointXY(0, 0)))
|
||||||
|
assert pr.addFeatures([f, f2, f3, f4, f5])
|
||||||
|
assert layer.featureCount() == 5
|
||||||
|
return layer
|
||||||
|
|
||||||
|
|
||||||
|
class TestQgsFeatureSource(unittest.TestCase):
|
||||||
|
|
||||||
|
def testUniqueValues(self):
|
||||||
|
"""
|
||||||
|
Test retrieving unique values using base class method
|
||||||
|
"""
|
||||||
|
|
||||||
|
# memory provider uses base class method
|
||||||
|
layer = createLayerWithFivePoints()
|
||||||
|
self.assertFalse(layer.dataProvider().uniqueValues(-1))
|
||||||
|
self.assertFalse(layer.dataProvider().uniqueValues(100))
|
||||||
|
self.assertEqual(layer.dataProvider().uniqueValues(0), {'test', 'test2', 'test3', 'test4'})
|
||||||
|
self.assertEqual(layer.dataProvider().uniqueValues(1), {1, 3, 3, 4})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user