Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Move methods for returning lists of values from a vector layer field
or expression to QgsVectorLayer. Add unit tests.
  • Loading branch information
nyalldawson committed May 2, 2015
1 parent fadaf12 commit bb0e583
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 39 deletions.
19 changes: 19 additions & 0 deletions python/core/qgsvectorlayer.sip
Expand Up @@ -1130,6 +1130,25 @@ class QgsVectorLayer : QgsMapLayer

/**Returns maximum value for an attribute column or invalid variant in case of error */
QVariant maximumValue( int index );

/** Fetches all values from a specified field name or expression.
* @param fieldOrExpression field name or an expression string
* @param ok will be set to false if field or expression is invalid, otherwise true
* @returns list of fetched values
* @note added in QGIS 2.9
* @see getDoubleValues
*/
QList< QVariant > getValues( const QString &fieldOrExpression, bool &ok );

/** Fetches all double values from a specified field name or expression. Null values or
* invalid expression results are skipped.
* @param fieldOrExpression field name or an expression string evaluating to a double value
* @param ok will be set to false if field or expression is invalid, otherwise true
* @returns list of fetched values
* @note added in QGIS 2.9
* @see getValues
*/
QList< double > getDoubleValues( const QString &fieldOrExpression, bool &ok );

/** Set the blending mode used for rendering each feature */
void setFeatureBlendMode( const QPainter::CompositionMode &blendMode );
Expand Down
3 changes: 2 additions & 1 deletion python/core/symbology-ng/qgsgraduatedsymbolrendererv2.sip
Expand Up @@ -155,7 +155,8 @@ class QgsGraduatedSymbolRendererV2 : QgsFeatureRendererV2
//! Evaluates the data expression and returns the list of values from the layer
//! @param vlayer The layer for which to evaluate the expression
//! @note Added in 2.6
QList<double> getDataValues( QgsVectorLayer *vlayer );
//! @deprecated use QgsVectorLayer::getDoubleValues instead
QList<double> getDataValues( QgsVectorLayer *vlayer ) /Deprecated/;

//! Return the label format used to generate default classification labels
//! @note Added in 2.6
Expand Down
61 changes: 61 additions & 0 deletions src/core/qgsvectorlayer.cpp
Expand Up @@ -3142,6 +3142,67 @@ QVariant QgsVectorLayer::maximumValue( int index )
return QVariant();
}

QList<QVariant> QgsVectorLayer::getValues( const QString &fieldOrExpression, bool& ok )
{
QList<QVariant> values;

QScopedPointer<QgsExpression> expression;
int attrNum = fieldNameIndex( fieldOrExpression );

if ( attrNum == -1 )
{
// try to use expression
expression.reset( new QgsExpression( fieldOrExpression ) );
if ( expression->hasParserError() || !expression->prepare( pendingFields() ) )
{
ok = false;
return values;
}
}

QgsFeature f;
QStringList lst;
if ( expression.isNull() )
lst.append( fieldOrExpression );
else
lst = expression->referencedColumns();

QgsFeatureIterator fit = getFeatures( QgsFeatureRequest()
.setFlags(( expression && expression->needsGeometry() ) ?
QgsFeatureRequest::NoFlags :
QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( lst, pendingFields() ) );

// create list of non-null attribute values
while ( fit.nextFeature( f ) )
{
QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
values << v;
}
ok = true;
return values;
}

QList<double> QgsVectorLayer::getDoubleValues( const QString &fieldOrExpression, bool& ok )
{
QList<double> values;

QList<QVariant> variantValues = getValues( fieldOrExpression, ok );
if ( !ok )
return values;

bool convertOk;
foreach ( QVariant value, variantValues )
{
double val = value.toDouble( &convertOk );
if ( convertOk )
values << val;
}
ok = true;
return values;
}


/** Write blend mode for features */
void QgsVectorLayer::setFeatureBlendMode( const QPainter::CompositionMode &featureBlendMode )
{
Expand Down
19 changes: 19 additions & 0 deletions src/core/qgsvectorlayer.h
Expand Up @@ -1493,6 +1493,25 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
/**Returns maximum value for an attribute column or invalid variant in case of error */
QVariant maximumValue( int index );

/** Fetches all values from a specified field name or expression.
* @param fieldOrExpression field name or an expression string
* @param ok will be set to false if field or expression is invalid, otherwise true
* @returns list of fetched values
* @note added in QGIS 2.9
* @see getDoubleValues
*/
QList< QVariant > getValues( const QString &fieldOrExpression, bool &ok );

/** Fetches all double values from a specified field name or expression. Null values or
* invalid expression results are skipped.
* @param fieldOrExpression field name or an expression string evaluating to a double value
* @param ok will be set to false if field or expression is invalid, otherwise true
* @returns list of fetched values
* @note added in QGIS 2.9
* @see getValues
*/
QList< double > getDoubleValues( const QString &fieldOrExpression, bool &ok );

/** Set the blending mode used for rendering each feature */
void setFeatureBlendMode( const QPainter::CompositionMode &blendMode );
/** Returns the current blending mode for features */
Expand Down
43 changes: 6 additions & 37 deletions src/core/symbology-ng/qgsgraduatedsymbolrendererv2.cpp
Expand Up @@ -817,40 +817,8 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::createRenderer(

QList<double> QgsGraduatedSymbolRendererV2::getDataValues( QgsVectorLayer *vlayer )
{
QList<double> values;

QScopedPointer<QgsExpression> expression;
int attrNum = vlayer->fieldNameIndex( mAttrName );

if ( attrNum == -1 )
{
// try to use expression
expression.reset( new QgsExpression( mAttrName ) );
if ( expression->hasParserError() || !expression->prepare( vlayer->pendingFields() ) )
return values; // should have a means to report errors
}

QgsFeature f;
QStringList lst;
if ( expression.isNull() )
lst.append( mAttrName );
else
lst = expression->referencedColumns();

QgsFeatureIterator fit = vlayer->getFeatures( QgsFeatureRequest()
.setFlags(( expression && expression->needsGeometry() ) ?
QgsFeatureRequest::NoFlags :
QgsFeatureRequest::NoGeometry )
.setSubsetOfAttributes( lst, vlayer->pendingFields() ) );

// create list of non-null attribute values
while ( fit.nextFeature( f ) )
{
QVariant v = expression ? expression->evaluate( f ) : f.attribute( attrNum );
if ( !v.isNull() )
values.append( v.toDouble() );
}
return values;
bool ok;
return vlayer->getDoubleValues( mAttrName, ok );
}

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

int attrNum = vlayer->fieldNameIndex( mAttrName );

bool ok;
if ( attrNum == -1 )
{
values = getDataValues( vlayer );
if ( values.isEmpty() )
values = vlayer->getDoubleValues( mAttrName, ok );
if ( !ok || values.isEmpty() )
return;

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

// calculate the breaks
Expand Down
4 changes: 3 additions & 1 deletion src/core/symbology-ng/qgsgraduatedsymbolrendererv2.h
Expand Up @@ -184,10 +184,12 @@ class CORE_EXPORT QgsGraduatedSymbolRendererV2 : public QgsFeatureRendererV2
//! @param nclasses The number of classes to calculate (approximate for some modes)
//! @note Added in 2.6
void updateClasses( QgsVectorLayer *vlayer, Mode mode, int nclasses );

//! Evaluates the data expression and returns the list of values from the layer
//! @param vlayer The layer for which to evaluate the expression
//! @note Added in 2.6
QList<double> getDataValues( QgsVectorLayer *vlayer );
//! @deprecated use QgsVectorLayer::getDoubleValues instead
Q_DECL_DEPRECATED QList<double> getDataValues( QgsVectorLayer *vlayer );

//! Return the label format used to generate default classification labels
//! @note Added in 2.6
Expand Down
48 changes: 48 additions & 0 deletions tests/src/core/testqgsvectorlayer.cpp
Expand Up @@ -194,6 +194,54 @@ class TestQgsVectorLayer : public QObject
QVERIFY( myCount == 3 );
}

void QgsVectorLayerGetValues()
{
QgsVectorLayer* layer = new QgsVectorLayer( "Point?field=col1:real", "layer", "memory" );
QVERIFY( layer->isValid() );
QgsFeature f1( layer->dataProvider()->fields(), 1 );
f1.setAttribute( "col1", 1 );
QgsFeature f2( layer->dataProvider()->fields(), 2 );
f2.setAttribute( "col1", 2 );
QgsFeature f3( layer->dataProvider()->fields(), 3 );
f3.setAttribute( "col1", 3 );
QgsFeature f4( layer->dataProvider()->fields(), 4 );
f4.setAttribute( "col1", QVariant() );
layer->dataProvider()->addFeatures( QgsFeatureList() << f1 << f2 << f3 << f4 );

bool ok;
QList<QVariant> varList = layer->getValues( "col1", ok );
QVERIFY( ok );
QCOMPARE( varList.length(), 4 );
QCOMPARE( varList.at( 0 ), QVariant( 1 ) );
QCOMPARE( varList.at( 1 ), QVariant( 2 ) );
QCOMPARE( varList.at( 2 ), QVariant( 3 ) );
QCOMPARE( varList.at( 3 ), QVariant() );

QList<double> doubleList = layer->getDoubleValues( "col1", ok );
QVERIFY( ok );
QCOMPARE( doubleList.length(), 3 );
QCOMPARE( doubleList.at( 0 ), 1.0 );
QCOMPARE( doubleList.at( 1 ), 2.0 );
QCOMPARE( doubleList.at( 2 ), 3.0 );

QList<QVariant> expVarList = layer->getValues( "tostring(col1) || ' '", ok );
QVERIFY( ok );
QCOMPARE( expVarList.length(), 4 );
QCOMPARE( expVarList.at( 0 ).toString(), QString( "1 " ) );
QCOMPARE( expVarList.at( 1 ).toString(), QString( "2 " ) );
QCOMPARE( expVarList.at( 2 ).toString(), QString( "3 " ) );
QCOMPARE( expVarList.at( 3 ), QVariant() );

QList<double> expDoubleList = layer->getDoubleValues( "col1 * 2", ok );
QVERIFY( ok );
QCOMPARE( expDoubleList.length(), 3 );
QCOMPARE( expDoubleList.at( 0 ), 2.0 );
QCOMPARE( expDoubleList.at( 1 ), 4.0 );
QCOMPARE( expDoubleList.at( 2 ), 6.0 );

delete layer;
}

void QgsVectorLayerstorageType() {}
void QgsVectorLayercapabilitiesString() {}
void QgsVectorLayerdataComment() {}
Expand Down

0 comments on commit bb0e583

Please sign in to comment.