mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-28 00:17:30 -05:00
Classifications on joined fields should only consider values which
are matched to layer's features (fix #9051)
This commit is contained in:
parent
cb4dbeafd1
commit
16eb1e14d0
@ -3136,12 +3136,12 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
||||
}
|
||||
|
||||
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||
if ( origin == QgsFields::OriginUnknown )
|
||||
switch ( origin )
|
||||
{
|
||||
case QgsFields::OriginUnknown:
|
||||
return;
|
||||
}
|
||||
|
||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
||||
case QgsFields::OriginProvider: //a provider field
|
||||
{
|
||||
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
||||
|
||||
@ -3172,29 +3172,22 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
||||
|
||||
return;
|
||||
}
|
||||
else if ( origin == QgsFields::OriginJoin )
|
||||
{
|
||||
int sourceLayerIndex;
|
||||
const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
|
||||
Q_ASSERT( join );
|
||||
|
||||
QgsVectorLayer *vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
|
||||
|
||||
if ( vl )
|
||||
vl->dataProvider()->uniqueValues( sourceLayerIndex, uniqueValues, limit );
|
||||
|
||||
return;
|
||||
}
|
||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
||||
{
|
||||
case QgsFields::OriginEdit:
|
||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
||||
if ( origin == QgsFields::OriginEdit && mEditBuffer->mDeletedFeatureIds.isEmpty() && mEditBuffer->mAddedFeatures.isEmpty() && !mEditBuffer->mDeletedAttributeIds.contains( index ) && mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||
if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||
mEditBuffer->mAddedFeatures.isEmpty() &&
|
||||
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||
{
|
||||
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
||||
return;
|
||||
}
|
||||
|
||||
// we need to go through each feature
|
||||
FALLTHROUGH
|
||||
//we need to go through each feature
|
||||
case QgsFields::OriginJoin:
|
||||
case QgsFields::OriginExpression:
|
||||
{
|
||||
QgsAttributeList attList;
|
||||
attList << index;
|
||||
|
||||
@ -3218,6 +3211,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
||||
uniqueValues = val.values();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
|
||||
}
|
||||
@ -3230,38 +3224,31 @@ QVariant QgsVectorLayer::minimumValue( int index )
|
||||
}
|
||||
|
||||
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||
if ( origin == QgsFields::OriginUnknown )
|
||||
|
||||
switch ( origin )
|
||||
{
|
||||
case QgsFields::OriginUnknown:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
||||
{
|
||||
case QgsFields::OriginProvider: //a provider field
|
||||
return mDataProvider->minimumValue( index );
|
||||
}
|
||||
else if ( origin == QgsFields::OriginJoin )
|
||||
{
|
||||
int sourceLayerIndex;
|
||||
const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
|
||||
Q_ASSERT( join );
|
||||
|
||||
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
|
||||
Q_ASSERT( vl );
|
||||
|
||||
return vl->minimumValue( sourceLayerIndex );
|
||||
}
|
||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
||||
case QgsFields::OriginEdit:
|
||||
{
|
||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
||||
if ( origin == QgsFields::OriginEdit &&
|
||||
mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||
if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||
mEditBuffer->mAddedFeatures.isEmpty() && !
|
||||
mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||
{
|
||||
return mDataProvider->minimumValue( index );
|
||||
}
|
||||
|
||||
}
|
||||
FALLTHROUGH
|
||||
// no choice but to go through all features
|
||||
case QgsFields::OriginExpression:
|
||||
case QgsFields::OriginJoin:
|
||||
{
|
||||
// we need to go through each feature
|
||||
QgsAttributeList attList;
|
||||
attList << index;
|
||||
@ -3283,6 +3270,7 @@ QVariant QgsVectorLayer::minimumValue( int index )
|
||||
}
|
||||
return QVariant( minimumValue );
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
|
||||
return QVariant();
|
||||
@ -3296,31 +3284,17 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
||||
}
|
||||
|
||||
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||
if ( origin == QgsFields::OriginUnknown )
|
||||
switch ( origin )
|
||||
{
|
||||
case QgsFields::OriginUnknown:
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
||||
{
|
||||
case QgsFields::OriginProvider: //a provider field
|
||||
return mDataProvider->maximumValue( index );
|
||||
}
|
||||
else if ( origin == QgsFields::OriginJoin )
|
||||
{
|
||||
int sourceLayerIndex;
|
||||
const QgsVectorJoinInfo* join = mJoinBuffer->joinForFieldIndex( index, mUpdatedFields, sourceLayerIndex );
|
||||
Q_ASSERT( join );
|
||||
|
||||
QgsVectorLayer* vl = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( join->joinLayerId ) );
|
||||
Q_ASSERT( vl );
|
||||
|
||||
return vl->maximumValue( sourceLayerIndex );
|
||||
}
|
||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
||||
{
|
||||
case QgsFields::OriginEdit:
|
||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
||||
if ( origin == QgsFields::OriginEdit &&
|
||||
mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||
if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||
mEditBuffer->mAddedFeatures.isEmpty() &&
|
||||
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||
@ -3328,7 +3302,11 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
||||
return mDataProvider->maximumValue( index );
|
||||
}
|
||||
|
||||
// we need to go through each feature
|
||||
FALLTHROUGH
|
||||
//no choice but to go through each feature
|
||||
case QgsFields::OriginJoin:
|
||||
case QgsFields::OriginExpression:
|
||||
{
|
||||
QgsAttributeList attList;
|
||||
attList << index;
|
||||
|
||||
@ -3349,6 +3327,7 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
||||
}
|
||||
return QVariant( maximumValue );
|
||||
}
|
||||
}
|
||||
|
||||
Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
|
||||
return QVariant();
|
||||
|
@ -59,6 +59,21 @@ def createLayerWithOnePoint():
|
||||
return layer
|
||||
|
||||
|
||||
def createLayerWithTwoPoints():
|
||||
layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer",
|
||||
"addfeat", "memory")
|
||||
pr = layer.dataProvider()
|
||||
f = QgsFeature()
|
||||
f.setAttributes(["test", 123])
|
||||
f.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
|
||||
f2 = QgsFeature()
|
||||
f2.setAttributes(["test2", 457])
|
||||
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(100, 200)))
|
||||
assert pr.addFeatures([f, f2])
|
||||
assert layer.pendingFeatureCount() == 2
|
||||
return layer
|
||||
|
||||
|
||||
def createJoinLayer():
|
||||
joinLayer = QgsVectorLayer(
|
||||
"Point?field=x:string&field=y:integer&field=z:integer",
|
||||
@ -70,8 +85,14 @@ def createJoinLayer():
|
||||
f2 = QgsFeature()
|
||||
f2.setAttributes(["bar", 456, 654])
|
||||
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
|
||||
assert pr.addFeatures([f1, f2])
|
||||
assert joinLayer.pendingFeatureCount() == 2
|
||||
f3 = QgsFeature()
|
||||
f3.setAttributes(["qar", 457, 111])
|
||||
f3.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
|
||||
f4 = QgsFeature()
|
||||
f4.setAttributes(["a", 458, 19])
|
||||
f4.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
|
||||
assert pr.addFeatures([f1, f2, f3, f4])
|
||||
assert joinLayer.pendingFeatureCount() == 4
|
||||
return joinLayer
|
||||
|
||||
|
||||
@ -1083,6 +1104,24 @@ class TestQgsVectorLayer(unittest.TestCase):
|
||||
self.assertEqual(f2[2], "foo")
|
||||
self.assertEqual(f2[3], 321)
|
||||
|
||||
def test_JoinStats(self):
|
||||
""" test calculating min/max/uniqueValues on joined field """
|
||||
joinLayer = createJoinLayer()
|
||||
layer = createLayerWithTwoPoints()
|
||||
QgsMapLayerRegistry.instance().addMapLayers([joinLayer, layer])
|
||||
|
||||
join = QgsVectorJoinInfo()
|
||||
join.targetFieldName = "fldint"
|
||||
join.joinLayerId = joinLayer.id()
|
||||
join.joinFieldName = "y"
|
||||
join.memoryCache = True
|
||||
layer.addJoin(join)
|
||||
|
||||
# stats on joined fields should only include values present by join
|
||||
self.assertEqual(layer.minimumValue(3), 111)
|
||||
self.assertEqual(layer.maximumValue(3), 321)
|
||||
self.assertEqual(set(layer.uniqueValues(3)), set([111, 321]))
|
||||
|
||||
def test_InvalidOperations(self):
|
||||
layer = createLayerWithOnePoint()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user