Skip to content

Commit 13c5848

Browse files
committed
Fix deselecting null category when categorising using expression
hides all features (fix #14273)
1 parent 4094bae commit 13c5848

File tree

2 files changed

+95
-21
lines changed

2 files changed

+95
-21
lines changed

src/core/symbology-ng/qgscategorizedsymbolrendererv2.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,8 @@ QString QgsCategorizedSymbolRendererV2::filter( const QgsFields& fields )
585585
}
586586
}
587587

588+
QString attr = isExpression ? mAttrName : QString( "\"%1\"" ).arg( mAttrName );
589+
588590
if ( allActive && hasDefault )
589591
{
590592
return QString();
@@ -595,11 +597,11 @@ QString QgsCategorizedSymbolRendererV2::filter( const QgsFields& fields )
595597
}
596598
else if ( defaultActive )
597599
{
598-
return QString( "(\"%1\") NOT IN (%2) OR (\"%1\") IS NULL" ).arg( mAttrName, inactiveValues );
600+
return QString( "(%1) NOT IN (%2) OR (%1) IS NULL" ).arg( attr, inactiveValues );
599601
}
600602
else
601603
{
602-
return QString( "(\"%1\") IN (%2)" ).arg( mAttrName, activeValues );
604+
return QString( "(%1) IN (%2)" ).arg( attr, activeValues );
603605
}
604606
}
605607

tests/src/python/test_qgscategorizedsymbolrendererv2.py

+91-19
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
QgsPoint,
2828
QgsSymbolV2,
2929
QgsSymbolLayerV2Utils,
30-
QgsRenderContext
30+
QgsRenderContext,
31+
QgsField,
32+
QgsFields
3133
)
3234
from PyQt4.QtCore import Qt, QVariant
3335
from PyQt4.QtXml import QDomDocument
@@ -58,58 +60,128 @@ def testFilter(self):
5860
# add default category
5961
renderer.addCategory(QgsRendererCategoryV2('', createMarkerSymbol(), 'default'))
6062

61-
self.assertEqual(renderer.filter(), '')
63+
fields = QgsFields()
64+
fields.append(QgsField('field', QVariant.String))
65+
fields.append(QgsField('num', QVariant.Double))
66+
67+
self.assertEqual(renderer.filter(fields), '')
6268
# remove categories, leaving default
6369
assert renderer.updateCategoryRenderState(0, False)
64-
self.assertEqual(renderer.filter(), "(\"field\") NOT IN ('a') OR (\"field\") IS NULL")
70+
self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a') OR (\"field\") IS NULL")
6571
assert renderer.updateCategoryRenderState(1, False)
66-
self.assertEqual(renderer.filter(), "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL")
72+
self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b') OR (\"field\") IS NULL")
6773
assert renderer.updateCategoryRenderState(2, False)
68-
self.assertEqual(renderer.filter(), "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL")
74+
self.assertEqual(renderer.filter(fields), "(\"field\") NOT IN ('a','b','c') OR (\"field\") IS NULL")
6975
# remove default category
7076
assert renderer.updateCategoryRenderState(3, False)
71-
self.assertEqual(renderer.filter(), "FALSE")
77+
self.assertEqual(renderer.filter(fields), "FALSE")
7278
# add back other categories, leaving default disabled
7379
assert renderer.updateCategoryRenderState(0, True)
74-
self.assertEqual(renderer.filter(), "(\"field\") IN ('a')")
80+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a')")
7581
assert renderer.updateCategoryRenderState(1, True)
76-
self.assertEqual(renderer.filter(), "(\"field\") IN ('a','b')")
82+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b')")
7783
assert renderer.updateCategoryRenderState(2, True)
78-
self.assertEqual(renderer.filter(), "(\"field\") IN ('a','b','c')")
84+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b','c')")
7985

8086
renderer.deleteAllCategories()
8187
# just default category
8288
renderer.addCategory(QgsRendererCategoryV2('', createMarkerSymbol(), 'default'))
83-
self.assertEqual(renderer.filter(), '')
89+
self.assertEqual(renderer.filter(fields), '')
8490
assert renderer.updateCategoryRenderState(0, False)
85-
self.assertEqual(renderer.filter(), 'FALSE')
91+
self.assertEqual(renderer.filter(fields), 'FALSE')
8692

8793
renderer.deleteAllCategories()
8894
# no default category
8995
renderer.addCategory(QgsRendererCategoryV2('a', createMarkerSymbol(), 'a'))
9096
renderer.addCategory(QgsRendererCategoryV2('b', createMarkerSymbol(), 'b'))
9197
renderer.addCategory(QgsRendererCategoryV2('c', createMarkerSymbol(), 'c'))
92-
self.assertEqual(renderer.filter(), "(\"field\") IN ('a','b','c')")
98+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('a','b','c')")
9399
assert renderer.updateCategoryRenderState(0, False)
94-
self.assertEqual(renderer.filter(), "(\"field\") IN ('b','c')")
100+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('b','c')")
95101
assert renderer.updateCategoryRenderState(2, False)
96-
self.assertEqual(renderer.filter(), "(\"field\") IN ('b')")
102+
self.assertEqual(renderer.filter(fields), "(\"field\") IN ('b')")
97103
assert renderer.updateCategoryRenderState(1, False)
98-
self.assertEqual(renderer.filter(), "FALSE")
104+
self.assertEqual(renderer.filter(fields), "FALSE")
99105

100106
renderer.deleteAllCategories()
107+
renderer.setClassAttribute('num')
101108
# numeric categories
102109
renderer.addCategory(QgsRendererCategoryV2(1, createMarkerSymbol(), 'a'))
103110
renderer.addCategory(QgsRendererCategoryV2(2, createMarkerSymbol(), 'b'))
104111
renderer.addCategory(QgsRendererCategoryV2(3, createMarkerSymbol(), 'c'))
105-
self.assertEqual(renderer.filter(), '(\"field\") IN (1,2,3)')
112+
self.assertEqual(renderer.filter(fields), '(\"num\") IN (1,2,3)')
106113
assert renderer.updateCategoryRenderState(0, False)
107-
self.assertEqual(renderer.filter(), "(\"field\") IN (2,3)")
114+
self.assertEqual(renderer.filter(fields), "(\"num\") IN (2,3)")
108115
assert renderer.updateCategoryRenderState(2, False)
109-
self.assertEqual(renderer.filter(), "(\"field\") IN (2)")
116+
self.assertEqual(renderer.filter(fields), "(\"num\") IN (2)")
117+
assert renderer.updateCategoryRenderState(1, False)
118+
self.assertEqual(renderer.filter(fields), "FALSE")
119+
120+
def testFilterExpression(self):
121+
"""Test filter creation with expression"""
122+
renderer = QgsCategorizedSymbolRendererV2()
123+
renderer.setClassAttribute('field + field2')
124+
125+
renderer.addCategory(QgsRendererCategoryV2('a', createMarkerSymbol(), 'a'))
126+
renderer.addCategory(QgsRendererCategoryV2('b', createMarkerSymbol(), 'b'))
127+
renderer.addCategory(QgsRendererCategoryV2('c', createMarkerSymbol(), 'c'))
128+
# add default category
129+
renderer.addCategory(QgsRendererCategoryV2('', createMarkerSymbol(), 'default'))
130+
131+
fields = QgsFields()
132+
fields.append(QgsField('field', QVariant.String))
133+
134+
self.assertEqual(renderer.filter(fields), '')
135+
# remove categories, leaving default
136+
assert renderer.updateCategoryRenderState(0, False)
137+
self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a') OR (field + field2) IS NULL")
110138
assert renderer.updateCategoryRenderState(1, False)
111-
self.assertEqual(renderer.filter(), "FALSE")
139+
self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b') OR (field + field2) IS NULL")
140+
assert renderer.updateCategoryRenderState(2, False)
141+
self.assertEqual(renderer.filter(fields), "(field + field2) NOT IN ('a','b','c') OR (field + field2) IS NULL")
142+
# remove default category
143+
assert renderer.updateCategoryRenderState(3, False)
144+
self.assertEqual(renderer.filter(fields), "FALSE")
145+
# add back other categories, leaving default disabled
146+
assert renderer.updateCategoryRenderState(0, True)
147+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a')")
148+
assert renderer.updateCategoryRenderState(1, True)
149+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a','b')")
150+
assert renderer.updateCategoryRenderState(2, True)
151+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a','b','c')")
112152

153+
renderer.deleteAllCategories()
154+
# just default category
155+
renderer.addCategory(QgsRendererCategoryV2('', createMarkerSymbol(), 'default'))
156+
self.assertEqual(renderer.filter(fields), '')
157+
assert renderer.updateCategoryRenderState(0, False)
158+
self.assertEqual(renderer.filter(fields), 'FALSE')
159+
160+
renderer.deleteAllCategories()
161+
# no default category
162+
renderer.addCategory(QgsRendererCategoryV2('a', createMarkerSymbol(), 'a'))
163+
renderer.addCategory(QgsRendererCategoryV2('b', createMarkerSymbol(), 'b'))
164+
renderer.addCategory(QgsRendererCategoryV2('c', createMarkerSymbol(), 'c'))
165+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('a','b','c')")
166+
assert renderer.updateCategoryRenderState(0, False)
167+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('b','c')")
168+
assert renderer.updateCategoryRenderState(2, False)
169+
self.assertEqual(renderer.filter(fields), "(field + field2) IN ('b')")
170+
assert renderer.updateCategoryRenderState(1, False)
171+
self.assertEqual(renderer.filter(fields), "FALSE")
172+
173+
renderer.deleteAllCategories()
174+
# numeric categories
175+
renderer.addCategory(QgsRendererCategoryV2(1, createMarkerSymbol(), 'a'))
176+
renderer.addCategory(QgsRendererCategoryV2(2, createMarkerSymbol(), 'b'))
177+
renderer.addCategory(QgsRendererCategoryV2(3, createMarkerSymbol(), 'c'))
178+
self.assertEqual(renderer.filter(fields), '(field + field2) IN (1,2,3)')
179+
assert renderer.updateCategoryRenderState(0, False)
180+
self.assertEqual(renderer.filter(fields), "(field + field2) IN (2,3)")
181+
assert renderer.updateCategoryRenderState(2, False)
182+
self.assertEqual(renderer.filter(fields), "(field + field2) IN (2)")
183+
assert renderer.updateCategoryRenderState(1, False)
184+
self.assertEqual(renderer.filter(fields), "FALSE")
113185

114186
if __name__ == "__main__":
115187
unittest.main()

0 commit comments

Comments
 (0)