Skip to content

Commit bb0e583

Browse files
committed
Move methods for returning lists of values from a vector layer field
or expression to QgsVectorLayer. Add unit tests.
1 parent fadaf12 commit bb0e583

File tree

7 files changed

+158
-39
lines changed

7 files changed

+158
-39
lines changed

python/core/qgsvectorlayer.sip

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,25 @@ class QgsVectorLayer : QgsMapLayer
11301130

11311131
/**Returns maximum value for an attribute column or invalid variant in case of error */
11321132
QVariant maximumValue( int index );
1133+
1134+
/** Fetches all values from a specified field name or expression.
1135+
* @param fieldOrExpression field name or an expression string
1136+
* @param ok will be set to false if field or expression is invalid, otherwise true
1137+
* @returns list of fetched values
1138+
* @note added in QGIS 2.9
1139+
* @see getDoubleValues
1140+
*/
1141+
QList< QVariant > getValues( const QString &fieldOrExpression, bool &ok );
1142+
1143+
/** Fetches all double values from a specified field name or expression. Null values or
1144+
* invalid expression results are skipped.
1145+
* @param fieldOrExpression field name or an expression string evaluating to a double value
1146+
* @param ok will be set to false if field or expression is invalid, otherwise true
1147+
* @returns list of fetched values
1148+
* @note added in QGIS 2.9
1149+
* @see getValues
1150+
*/
1151+
QList< double > getDoubleValues( const QString &fieldOrExpression, bool &ok );
11331152

11341153
/** Set the blending mode used for rendering each feature */
11351154
void setFeatureBlendMode( const QPainter::CompositionMode &blendMode );

python/core/symbology-ng/qgsgraduatedsymbolrendererv2.sip

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,8 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
155155
//! Evaluates the data expression and returns the list of values from the layer
156156
//! @param vlayer The layer for which to evaluate the expression
157157
//! @note Added in 2.6
158-
QList<double> getDataValues( QgsVectorLayer *vlayer );
158+
//! @deprecated use QgsVectorLayer::getDoubleValues instead
159+
QList<double> getDataValues( QgsVectorLayer *vlayer ) /Deprecated/;
159160

160161
//! Return the label format used to generate default classification labels
161162
//! @note Added in 2.6

src/core/qgsvectorlayer.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3142,6 +3142,67 @@ QVariant QgsVectorLayer::maximumValue( int index )
31423142
return QVariant();
31433143
}
31443144

3145+
QList<QVariant> QgsVectorLayer::getValues( const QString &fieldOrExpression, bool& ok )
3146+
{
3147+
QList<QVariant> values;
3148+
3149+
QScopedPointer<QgsExpression> expression;
3150+
int attrNum = fieldNameIndex( fieldOrExpression );
3151+
3152+
if ( attrNum == -1 )
3153+
{
3154+
// try to use expression
3155+
expression.reset( new QgsExpression( fieldOrExpression ) );
3156+
if ( expression->hasParserError() || !expression->prepare( pendingFields() ) )
3157+
{
3158+
ok = false;
3159+
return values;
3160+
}
3161+
}
3162+
3163+
QgsFeature f;
3164+
QStringList lst;
3165+
if ( expression.isNull() )
3166+
lst.append( fieldOrExpression );
3167+
else
3168+
lst = expression->referencedColumns();
3169+
3170+
QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
3171+
.setFlags(( expression && expression->needsGeometry() ) ?
3172+
QgsFeatureRequest::NoFlags :
3173+
QgsFeatureRequest::NoGeometry )
3174+
.setSubsetOfAttributes( lst, pendingFields() ) );
3175+
3176+
// create list of non-null attribute values
3177+
while ( fit.nextFeature( f ) )
3178+
{
3179+
QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
3180+
values << v;
3181+
}
3182+
ok = true;
3183+
return values;
3184+
}
3185+
3186+
QList<double> QgsVectorLayer::getDoubleValues( const QString &fieldOrExpression, bool& ok )
3187+
{
3188+
QList<double> values;
3189+
3190+
QList<QVariant> variantValues = getValues( fieldOrExpression, ok );
3191+
if ( !ok )
3192+
return values;
3193+
3194+
bool convertOk;
3195+
foreach ( QVariant value, variantValues )
3196+
{
3197+
double val = value.toDouble( &convertOk );
3198+
if ( convertOk )
3199+
values << val;
3200+
}
3201+
ok = true;
3202+
return values;
3203+
}
3204+
3205+
31453206
/** Write blend mode for features */
31463207
void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode &featureBlendMode )
31473208
{

src/core/qgsvectorlayer.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1493,6 +1493,25 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
14931493
/**Returns maximum value for an attribute column or invalid variant in case of error */
14941494
QVariant maximumValue( int index );
14951495

1496+
/** Fetches all values from a specified field name or expression.
1497+
* @param fieldOrExpression field name or an expression string
1498+
* @param ok will be set to false if field or expression is invalid, otherwise true
1499+
* @returns list of fetched values
1500+
* @note added in QGIS 2.9
1501+
* @see getDoubleValues
1502+
*/
1503+
QList< QVariant > getValues( const QString &fieldOrExpression, bool &ok );
1504+
1505+
/** Fetches all double values from a specified field name or expression. Null values or
1506+
* invalid expression results are skipped.
1507+
* @param fieldOrExpression field name or an expression string evaluating to a double value
1508+
* @param ok will be set to false if field or expression is invalid, otherwise true
1509+
* @returns list of fetched values
1510+
* @note added in QGIS 2.9
1511+
* @see getValues
1512+
*/
1513+
QList< double > getDoubleValues( const QString &fieldOrExpression, bool &ok );
1514+
14961515
/** Set the blending mode used for rendering each feature */
14971516
void setFeatureBlendMode( const QPainter::CompositionMode &blendMode );
14981517
/** Returns the current blending mode for features */

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -817,40 +817,8 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(
817817

818818
QList<double> QgsGraduatedSymbolRendererV2::getDataValues( QgsVectorLayer *vlayer )
819819
{
820-
QList<double> values;
821-
822-
QScopedPointer<QgsExpression> expression;
823-
int attrNum = vlayer->fieldNameIndex( mAttrName );
824-
825-
if ( attrNum == -1 )
826-
{
827-
// try to use expression
828-
expression.reset( new QgsExpression( mAttrName ) );
829-
if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
830-
return values; // should have a means to report errors
831-
}
832-
833-
QgsFeature f;
834-
QStringList lst;
835-
if ( expression.isNull() )
836-
lst.append( mAttrName );
837-
else
838-
lst = expression->referencedColumns();
839-
840-
QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest()
841-
.setFlags(( expression && expression->needsGeometry() ) ?
842-
QgsFeatureRequest::NoFlags :
843-
QgsFeatureRequest::NoGeometry )
844-
.setSubsetOfAttributes( lst, vlayer->pendingFields() ) );
845-
846-
// create list of non-null attribute values
847-
while ( fit.nextFeature( f ) )
848-
{
849-
QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
850-
if ( !v.isNull() )
851-
values.append( v.toDouble() );
852-
}
853-
return values;
820+
bool ok;
821+
return vlayer->getDoubleValues( mAttrName, ok );
854822
}
855823

856824
void QgsGraduatedSymbolRendererV2::updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses )
@@ -873,10 +841,11 @@ void QgsGraduatedSymbolRendererV2::updateClasses( QgsVectorLayer *vlayer, Mode m
873841

874842
int attrNum = vlayer->fieldNameIndex( mAttrName );
875843

844+
bool ok;
876845
if ( attrNum == -1 )
877846
{
878-
values = getDataValues( vlayer );
879-
if ( values.isEmpty() )
847+
values = vlayer->getDoubleValues( mAttrName, ok );
848+
if ( !ok || values.isEmpty() )
880849
return;
881850

882851
qSort( values ); // vmora: is wondering if O( n log(n) ) is really necessary here, min and max are O( n )
@@ -906,7 +875,7 @@ void QgsGraduatedSymbolRendererV2::updateClasses( QgsVectorLayer *vlayer, Mode m
906875
// get values from layer
907876
if ( !valuesLoaded )
908877
{
909-
values = getDataValues( vlayer );
878+
values = vlayer->getDoubleValues( mAttrName, ok );
910879
}
911880

912881
// calculate the breaks

src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,12 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
184184
//! @param nclasses The number of classes to calculate (approximate for some modes)
185185
//! @note Added in 2.6
186186
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );
187+
187188
//! Evaluates the data expression and returns the list of values from the layer
188189
//! @param vlayer The layer for which to evaluate the expression
189190
//! @note Added in 2.6
190-
QList<double> getDataValues( QgsVectorLayer *vlayer );
191+
//! @deprecated use QgsVectorLayer::getDoubleValues instead
192+
Q_DECL_DEPRECATED QList<double> getDataValues( QgsVectorLayer *vlayer );
191193

192194
//! Return the label format used to generate default classification labels
193195
//! @note Added in 2.6

tests/src/core/testqgsvectorlayer.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,54 @@ class TestQgsVectorLayer : public QObject
194194
QVERIFY( myCount == 3 );
195195
}
196196

197+
void QgsVectorLayerGetValues()
198+
{
199+
QgsVectorLayer* layer = new QgsVectorLayer( "Point?field=col1:real", "layer", "memory" );
200+
QVERIFY( layer->isValid() );
201+
QgsFeature f1( layer->dataProvider()->fields(), 1 );
202+
f1.setAttribute( "col1", 1 );
203+
QgsFeature f2( layer->dataProvider()->fields(), 2 );
204+
f2.setAttribute( "col1", 2 );
205+
QgsFeature f3( layer->dataProvider()->fields(), 3 );
206+
f3.setAttribute( "col1", 3 );
207+
QgsFeature f4( layer->dataProvider()->fields(), 4 );
208+
f4.setAttribute( "col1", QVariant() );
209+
layer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );
210+
211+
bool ok;
212+
QList<QVariant> varList = layer->getValues( "col1", ok );
213+
QVERIFY( ok );
214+
QCOMPARE( varList.length(), 4 );
215+
QCOMPARE( varList.at( 0 ), QVariant( 1 ) );
216+
QCOMPARE( varList.at( 1 ), QVariant( 2 ) );
217+
QCOMPARE( varList.at( 2 ), QVariant( 3 ) );
218+
QCOMPARE( varList.at( 3 ), QVariant() );
219+
220+
QList<double> doubleList = layer->getDoubleValues( "col1", ok );
221+
QVERIFY( ok );
222+
QCOMPARE( doubleList.length(), 3 );
223+
QCOMPARE( doubleList.at( 0 ), 1.0 );
224+
QCOMPARE( doubleList.at( 1 ), 2.0 );
225+
QCOMPARE( doubleList.at( 2 ), 3.0 );
226+
227+
QList<QVariant> expVarList = layer->getValues( "tostring(col1) || ' '", ok );
228+
QVERIFY( ok );
229+
QCOMPARE( expVarList.length(), 4 );
230+
QCOMPARE( expVarList.at( 0 ).toString(), QString( "1 " ) );
231+
QCOMPARE( expVarList.at( 1 ).toString(), QString( "2 " ) );
232+
QCOMPARE( expVarList.at( 2 ).toString(), QString( "3 " ) );
233+
QCOMPARE( expVarList.at( 3 ), QVariant() );
234+
235+
QList<double> expDoubleList = layer->getDoubleValues( "col1 * 2", ok );
236+
QVERIFY( ok );
237+
QCOMPARE( expDoubleList.length(), 3 );
238+
QCOMPARE( expDoubleList.at( 0 ), 2.0 );
239+
QCOMPARE( expDoubleList.at( 1 ), 4.0 );
240+
QCOMPARE( expDoubleList.at( 2 ), 6.0 );
241+
242+
delete layer;
243+
}
244+
197245
void QgsVectorLayerstorageType() {}
198246
void QgsVectorLayercapabilitiesString() {}
199247
void QgsVectorLayerdataComment() {}

0 commit comments

Comments
 (0)