From c58187cf0245d3f12ce6487189eae1c163d08cdd Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 17 Aug 2016 14:34:44 +1000 Subject: [PATCH] Make QgsVectorLayer uniqueValues/min/maxValue consider edits Previously these methods would inconsistently handle the edit buffer, eg uniqueValues would consider changed attributes but not added features. Now uniqueValues, minimumValue and maximumValue all consider both added features and changed attribute values when performing their calculation. The most noticable effect of this fix is that the unique values widget now correctly shows values for features which have been added but not yet committed to the provider. (cherry-picked from 50c35929d86ab01b22c29cd129fd7019a1bf624a) --- python/core/qgsvectorlayer.sip | 26 ++++++++++-- src/core/qgsvectorlayer.cpp | 77 +++++++++++++++++++++++++++++++++- src/core/qgsvectorlayer.h | 26 ++++++++++-- 3 files changed, 119 insertions(+), 10 deletions(-) diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index a1784caa2a11..3a5fbbcfedfd 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -1317,17 +1317,35 @@ class QgsVectorLayer : QgsMapLayer /** Caches joined attributes if required (and not already done) */ void createJoinCaches(); - /** Returns unique values for column + /** 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 limit maximum number of values to return (-1 if unlimited) + * @param limit maximum number of values to return (or -1 if unlimited) + * @see minimumValue() + * @see maximumValue() */ void uniqueValues( int index, QList &uniqueValues /Out/, int limit = -1 ); - /** Returns minimum value for an attribute column or invalid variant in case of error */ + /** Returns the minimum value for an attribute column or an invalid variant in case of error. + * Note that in some circumstances when unsaved changes are present for the layer then the + * returned value may be outdated (for instance when the attribute value in a saved feature has + * been changed inside the edit buffer then the previous saved value may be returned as the minimum). + * @see maximumValue() + * @see uniqueValues() + */ QVariant minimumValue( int index ); - /** Returns maximum value for an attribute column or invalid variant in case of error */ + /** Returns the maximum value for an attribute column or an invalid variant in case of error. + * Note that in some circumstances when unsaved changes are present for the layer then the + * returned value may be outdated (for instance when the attribute value in a saved feature has + * been changed inside the edit buffer then the previous saved value may be returned as the maximum). + * @see minimumValue() + * @see uniqueValues() + */ QVariant maximumValue( int index ); /** Calculates an aggregated value from the layer's features. diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 6149e598c48c..1071b65f479b 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -3156,6 +3156,23 @@ void QgsVectorLayer::uniqueValues( int index, QList &uniqueValues, int vals << v.toString(); } + QgsFeatureMap added = mEditBuffer->addedFeatures(); + QMapIterator< QgsFeatureId, QgsFeature > addedIt( added ); + while ( addedIt.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) ) + { + addedIt.next(); + QVariant v = addedIt.value().attribute( index ); + if ( v.isValid() ) + { + QString vs = v.toString(); + if ( !vals.contains( vs ) ) + { + vals << vs; + uniqueValues << v; + } + } + } + QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() ); while ( it.hasNext() && ( limit < 0 || uniqueValues.count() < limit ) ) { @@ -3234,7 +3251,35 @@ QVariant QgsVectorLayer::minimumValue( int index ) return QVariant(); case QgsFields::OriginProvider: //a provider field - return mDataProvider->minimumValue( index ); + { + QVariant min = mDataProvider->minimumValue( index ); + if ( mEditBuffer ) + { + QgsFeatureMap added = mEditBuffer->addedFeatures(); + QMapIterator< QgsFeatureId, QgsFeature > addedIt( added ); + while ( addedIt.hasNext() ) + { + addedIt.next(); + QVariant v = addedIt.value().attribute( index ); + if ( v.isValid() && qgsVariantLessThan( v, min ) ) + { + min = v; + } + } + + QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() ); + while ( it.hasNext() ) + { + it.next(); + QVariant v = it.value().value( index ); + if ( v.isValid() && qgsVariantLessThan( v, min ) ) + { + min = v; + } + } + } + return min; + } case QgsFields::OriginEdit: { @@ -3293,7 +3338,35 @@ QVariant QgsVectorLayer::maximumValue( int index ) return QVariant(); case QgsFields::OriginProvider: //a provider field - return mDataProvider->maximumValue( index ); + { + QVariant min = mDataProvider->maximumValue( index ); + if ( mEditBuffer ) + { + QgsFeatureMap added = mEditBuffer->addedFeatures(); + QMapIterator< QgsFeatureId, QgsFeature > addedIt( added ); + while ( addedIt.hasNext() ) + { + addedIt.next(); + QVariant v = addedIt.value().attribute( index ); + if ( v.isValid() && qgsVariantGreaterThan( v, min ) ) + { + min = v; + } + } + + QMapIterator< QgsFeatureId, QgsAttributeMap > it( mEditBuffer->changedAttributeValues() ); + while ( it.hasNext() ) + { + it.next(); + QVariant v = it.value().value( index ); + if ( v.isValid() && qgsVariantGreaterThan( v, min ) ) + { + min = v; + } + } + } + return min; + } case QgsFields::OriginEdit: // the layer is editable, but in certain cases it can still be avoided going through all features diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 0d7c646a9c65..6bad31860e77 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -1707,17 +1707,35 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer /** Caches joined attributes if required (and not already done) */ void createJoinCaches(); - /** Returns unique values for column + /** 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 limit maximum number of values to return (-1 if unlimited) + * @param limit maximum number of values to return (or -1 if unlimited) + * @see minimumValue() + * @see maximumValue() */ void uniqueValues( int index, QList &uniqueValues, int limit = -1 ); - /** Returns minimum value for an attribute column or invalid variant in case of error */ + /** Returns the minimum value for an attribute column or an invalid variant in case of error. + * Note that in some circumstances when unsaved changes are present for the layer then the + * returned value may be outdated (for instance when the attribute value in a saved feature has + * been changed inside the edit buffer then the previous saved value may be returned as the minimum). + * @see maximumValue() + * @see uniqueValues() + */ QVariant minimumValue( int index ); - /** Returns maximum value for an attribute column or invalid variant in case of error */ + /** Returns the maximum value for an attribute column or an invalid variant in case of error. + * Note that in some circumstances when unsaved changes are present for the layer then the + * returned value may be outdated (for instance when the attribute value in a saved feature has + * been changed inside the edit buffer then the previous saved value may be returned as the maximum). + * @see minimumValue() + * @see uniqueValues() + */ QVariant maximumValue( int index ); /** Calculates an aggregated value from the layer's features.