mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-27 00:03:38 -04: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 );
|
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||||
if ( origin == QgsFields::OriginUnknown )
|
switch ( origin )
|
||||||
{
|
{
|
||||||
|
case QgsFields::OriginUnknown:
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
case QgsFields::OriginProvider: //a provider field
|
||||||
{
|
{
|
||||||
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
||||||
|
|
||||||
@ -3172,29 +3172,22 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
|
|
||||||
return;
|
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 ) );
|
case QgsFields::OriginEdit:
|
||||||
|
|
||||||
if ( vl )
|
|
||||||
vl->dataProvider()->uniqueValues( sourceLayerIndex, uniqueValues, limit );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
|
||||||
{
|
|
||||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
// 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 );
|
mDataProvider->uniqueValues( index, uniqueValues, limit );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
FALLTHROUGH
|
||||||
//we need to go through each feature
|
//we need to go through each feature
|
||||||
|
case QgsFields::OriginJoin:
|
||||||
|
case QgsFields::OriginExpression:
|
||||||
|
{
|
||||||
QgsAttributeList attList;
|
QgsAttributeList attList;
|
||||||
attList << index;
|
attList << index;
|
||||||
|
|
||||||
@ -3218,6 +3211,7 @@ void QgsVectorLayer::uniqueValues( int index, QList<QVariant> &uniqueValues, int
|
|||||||
uniqueValues = val.values();
|
uniqueValues = val.values();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Q_ASSERT_X( false, "QgsVectorLayer::uniqueValues()", "Unknown source of the field!" );
|
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 );
|
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||||
if ( origin == QgsFields::OriginUnknown )
|
|
||||||
|
switch ( origin )
|
||||||
{
|
{
|
||||||
|
case QgsFields::OriginUnknown:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
|
||||||
|
|
||||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
case QgsFields::OriginProvider: //a provider field
|
||||||
{
|
|
||||||
return mDataProvider->minimumValue( index );
|
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 ) );
|
case QgsFields::OriginEdit:
|
||||||
Q_ASSERT( vl );
|
|
||||||
|
|
||||||
return vl->minimumValue( sourceLayerIndex );
|
|
||||||
}
|
|
||||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
|
||||||
{
|
{
|
||||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
// the layer is editable, but in certain cases it can still be avoided going through all features
|
||||||
if ( origin == QgsFields::OriginEdit &&
|
if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||||
mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
|
||||||
mEditBuffer->mAddedFeatures.isEmpty() && !
|
mEditBuffer->mAddedFeatures.isEmpty() && !
|
||||||
mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||||
{
|
{
|
||||||
return mDataProvider->minimumValue( index );
|
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
|
// we need to go through each feature
|
||||||
QgsAttributeList attList;
|
QgsAttributeList attList;
|
||||||
attList << index;
|
attList << index;
|
||||||
@ -3283,6 +3270,7 @@ QVariant QgsVectorLayer::minimumValue( int index )
|
|||||||
}
|
}
|
||||||
return QVariant( minimumValue );
|
return QVariant( minimumValue );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
|
Q_ASSERT_X( false, "QgsVectorLayer::minimumValue()", "Unknown source of the field!" );
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -3296,31 +3284,17 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
|||||||
}
|
}
|
||||||
|
|
||||||
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
QgsFields::FieldOrigin origin = mUpdatedFields.fieldOrigin( index );
|
||||||
if ( origin == QgsFields::OriginUnknown )
|
switch ( origin )
|
||||||
{
|
{
|
||||||
|
case QgsFields::OriginUnknown:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
|
||||||
|
|
||||||
if ( origin == QgsFields::OriginProvider ) //a provider field
|
case QgsFields::OriginProvider: //a provider field
|
||||||
{
|
|
||||||
return mDataProvider->maximumValue( index );
|
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 ) );
|
case QgsFields::OriginEdit:
|
||||||
Q_ASSERT( vl );
|
|
||||||
|
|
||||||
return vl->maximumValue( sourceLayerIndex );
|
|
||||||
}
|
|
||||||
else if ( origin == QgsFields::OriginEdit || origin == QgsFields::OriginExpression )
|
|
||||||
{
|
|
||||||
// the layer is editable, but in certain cases it can still be avoided going through all features
|
// the layer is editable, but in certain cases it can still be avoided going through all features
|
||||||
if ( origin == QgsFields::OriginEdit &&
|
if ( mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
||||||
mEditBuffer->mDeletedFeatureIds.isEmpty() &&
|
|
||||||
mEditBuffer->mAddedFeatures.isEmpty() &&
|
mEditBuffer->mAddedFeatures.isEmpty() &&
|
||||||
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
!mEditBuffer->mDeletedAttributeIds.contains( index ) &&
|
||||||
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
mEditBuffer->mChangedAttributeValues.isEmpty() )
|
||||||
@ -3328,7 +3302,11 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
|||||||
return mDataProvider->maximumValue( 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;
|
QgsAttributeList attList;
|
||||||
attList << index;
|
attList << index;
|
||||||
|
|
||||||
@ -3349,6 +3327,7 @@ QVariant QgsVectorLayer::maximumValue( int index )
|
|||||||
}
|
}
|
||||||
return QVariant( maximumValue );
|
return QVariant( maximumValue );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
|
Q_ASSERT_X( false, "QgsVectorLayer::maximumValue()", "Unknown source of the field!" );
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
@ -59,6 +59,21 @@ def createLayerWithOnePoint():
|
|||||||
return layer
|
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():
|
def createJoinLayer():
|
||||||
joinLayer = QgsVectorLayer(
|
joinLayer = QgsVectorLayer(
|
||||||
"Point?field=x:string&field=y:integer&field=z:integer",
|
"Point?field=x:string&field=y:integer&field=z:integer",
|
||||||
@ -70,8 +85,14 @@ def createJoinLayer():
|
|||||||
f2 = QgsFeature()
|
f2 = QgsFeature()
|
||||||
f2.setAttributes(["bar", 456, 654])
|
f2.setAttributes(["bar", 456, 654])
|
||||||
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
|
f2.setGeometry(QgsGeometry.fromPoint(QgsPoint(2, 2)))
|
||||||
assert pr.addFeatures([f1, f2])
|
f3 = QgsFeature()
|
||||||
assert joinLayer.pendingFeatureCount() == 2
|
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
|
return joinLayer
|
||||||
|
|
||||||
|
|
||||||
@ -1083,6 +1104,24 @@ class TestQgsVectorLayer(unittest.TestCase):
|
|||||||
self.assertEqual(f2[2], "foo")
|
self.assertEqual(f2[2], "foo")
|
||||||
self.assertEqual(f2[3], 321)
|
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):
|
def test_InvalidOperations(self):
|
||||||
layer = createLayerWithOnePoint()
|
layer = createLayerWithOnePoint()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user