Skip to content

Commit 25832b3

Browse files
committed
[server] Implement LAYERFONTCOLOR and ITEMFONTCOLORa
cherry-picking commit dca0fb9.
1 parent 1fac5a6 commit 25832b3

File tree

13 files changed

+210
-28
lines changed

13 files changed

+210
-28
lines changed

python/core/auto_generated/qgslegendsettings.sip.in

+24
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,30 @@ Returns style
7575
QColor fontColor() const;
7676
void setFontColor( const QColor &c );
7777

78+
QColor layerFontColor() const;
79+
%Docstring
80+
Returns layer font color, defaults to fontColor()
81+
82+
.. seealso:: :py:func:`setLayerFontColor`
83+
84+
.. seealso:: :py:func:`fontColor`
85+
86+
.. versionadded:: 3.4.7
87+
%End
88+
89+
void setLayerFontColor( const QColor &fontColor );
90+
%Docstring
91+
Sets layer font color to ``fontColor``
92+
Overrides fontColor()
93+
94+
.. seealso:: :py:func:`layerFontColor`
95+
96+
.. seealso:: :py:func:`fontColor`
97+
98+
.. versionadded:: 3.4.7
99+
%End
100+
101+
78102
QSizeF symbolSize() const;
79103
void setSymbolSize( QSizeF s );
80104

src/core/qgslegendrenderer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,9 @@ QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer,
585585
double y = point.y();
586586

587587
if ( context && context->painter() )
588-
context->painter()->setPen( mSettings.fontColor() );
588+
context->painter()->setPen( mSettings.layerFontColor() );
589589
else if ( painter )
590-
painter->setPen( mSettings.fontColor() );
590+
painter->setPen( mSettings.layerFontColor() );
591591

592592
QFont layerFont = mSettings.style( nodeLegendStyle( nodeLayer ) ).font();
593593

src/core/qgslegendsettings.h

+21
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,24 @@ class CORE_EXPORT QgsLegendSettings
8888
QColor fontColor() const {return mFontColor;}
8989
void setFontColor( const QColor &c ) {mFontColor = c;}
9090

91+
/**
92+
* Returns layer font color, defaults to fontColor()
93+
* \see setLayerFontColor()
94+
* \see fontColor()
95+
* \since QGIS 3.4.7
96+
*/
97+
QColor layerFontColor() const {return mLayerFontColor.isValid() ? mLayerFontColor : fontColor() ;}
98+
99+
/**
100+
* Sets layer font color to \a fontColor
101+
* Overrides fontColor()
102+
* \see layerFontColor()
103+
* \see fontColor()
104+
* \since QGIS 3.4.7
105+
*/
106+
void setLayerFontColor( const QColor &fontColor ) {mLayerFontColor = fontColor;}
107+
108+
91109
QSizeF symbolSize() const {return mSymbolSize;}
92110
void setSymbolSize( QSizeF s ) {mSymbolSize = s;}
93111

@@ -306,6 +324,9 @@ class CORE_EXPORT QgsLegendSettings
306324

307325
//! DPI to be used when rendering legend
308326
int mDpi = 96;
327+
328+
//! Font color for layers, overrides font color
329+
QColor mLayerFontColor;
309330
};
310331

311332

src/server/services/wms/qgswmsparameters.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,16 @@ namespace QgsWms
10991099
return mWmsParameters[ QgsWmsParameter::ITEMFONTSIZE ].toDouble();
11001100
}
11011101

1102+
QString QgsWmsParameters::itemFontColor() const
1103+
{
1104+
return mWmsParameters[ QgsWmsParameter::ITEMFONTCOLOR ].toString();
1105+
}
1106+
1107+
QColor QgsWmsParameters::itemFontColorAsColor() const
1108+
{
1109+
return mWmsParameters[ QgsWmsParameter::ITEMFONTCOLOR ].toColor();
1110+
}
1111+
11021112
QFont QgsWmsParameters::layerFont() const
11031113
{
11041114
QFont font;
@@ -1153,6 +1163,18 @@ namespace QgsWms
11531163
settings.rstyle( QgsLegendStyle::Style::Subgroup ).setMargin( QgsLegendStyle::Side::Bottom, layerTitleSpaceAsDouble() );
11541164
settings.rstyle( QgsLegendStyle::Style::Subgroup ).setFont( layerFont() );
11551165

1166+
if ( !itemFontColor().isEmpty() )
1167+
{
1168+
settings.setFontColor( itemFontColorAsColor() );
1169+
}
1170+
1171+
// Ok, this is tricky: because QgsLegendSettings's layerFontColor was added to the API after
1172+
// fontColor, to fix regressions #21871 and #21870 and the previous behavior was to use fontColor
1173+
// for the whole legend we need to preserve that behavior.
1174+
// But, the 2.18 server parameters ITEMFONTCOLOR did not have effect on the layer titles too, so
1175+
// we set explicitly layerFontColor to black if it's not overridden by LAYERFONTCOLOR argument.
1176+
settings.setLayerFontColor( layerFontColor().isEmpty() ? QColor( Qt::black ) : layerFontColorAsColor() );
1177+
11561178
settings.rstyle( QgsLegendStyle::Style::SymbolLabel ).setFont( itemFont() );
11571179
settings.rstyle( QgsLegendStyle::Style::Symbol ).setMargin( QgsLegendStyle::Side::Top, symbolSpaceAsDouble() );
11581180
settings.rstyle( QgsLegendStyle::Style::SymbolLabel ).setMargin( QgsLegendStyle::Side::Left, iconLabelSpaceAsDouble() );

src/server/services/wms/qgswmsparameters.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ namespace QgsWms
186186
/**
187187
* Default destructor for QgsWmsParameter.
188188
*/
189-
virtual ~QgsWmsParameter() = default;
189+
virtual ~QgsWmsParameter() override = default;
190190

191191
/**
192192
* Returns true if the parameter is valid, false otherwise.
@@ -335,7 +335,7 @@ namespace QgsWms
335335
*/
336336
QgsWmsParameters();
337337

338-
virtual ~QgsWmsParameters() = default;
338+
virtual ~QgsWmsParameters() override = default;
339339

340340
/**
341341
* Dumps parameters.

tests/src/python/test_qgsserver_wms_getlegendgraphic.py

+139-24
Original file line numberDiff line numberDiff line change
@@ -62,27 +62,6 @@ def test_getLegendGraphics(self):
6262
self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r))
6363
self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r))
6464

65-
def test_getLegendGraphics_invalid_parameters(self):
66-
"""Test that does return an exception"""
67-
qs = "?" + "&".join(["%s=%s" % i for i in list({
68-
"MAP": urllib.parse.quote(self.projectPath),
69-
"SERVICE": "WMS",
70-
"VERSION": "1.1.1",
71-
"REQUEST": "GetLegendGraphic",
72-
"LAYER": "Country,Hello,db_point",
73-
"LAYERTITLE": "FALSE",
74-
"FORMAT": "image/png",
75-
"HEIGHT": "500",
76-
"WIDTH": "500",
77-
"RULE": "1",
78-
"BBOX": "-151.7,-38.9,51.0,78.0",
79-
"CRS": "EPSG:4326"
80-
}.items())])
81-
82-
r, h = self._result(self._execute_request(qs))
83-
err = b"BBOX parameter cannot be combined with RULE" in r
84-
self.assertTrue(err)
85-
8665
def test_wms_GetLegendGraphic_LayerSpace(self):
8766
qs = "?" + "&".join(["%s=%s" % i for i in list({
8867
"MAP": urllib.parse.quote(self.projectPath),
@@ -107,6 +86,27 @@ def test_wms_GetLegendGraphic_LayerSpace(self):
10786
r, h = self._result(self._execute_request(qs))
10887
self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerSpace", max_size_diff=QSize(1, 1))
10988

89+
def test_wms_getLegendGraphics_invalid_parameters(self):
90+
"""Test that does return an exception"""
91+
qs = "?" + "&".join(["%s=%s" % i for i in list({
92+
"MAP": urllib.parse.quote(self.projectPath),
93+
"SERVICE": "WMS",
94+
"VERSION": "1.1.1",
95+
"REQUEST": "GetLegendGraphic",
96+
"LAYER": "Country,Hello,db_point",
97+
"LAYERTITLE": "FALSE",
98+
"FORMAT": "image/png",
99+
"HEIGHT": "500",
100+
"WIDTH": "500",
101+
"RULE": "1",
102+
"BBOX": "-151.7,-38.9,51.0,78.0",
103+
"CRS": "EPSG:4326"
104+
}.items())])
105+
106+
r, h = self._result(self._execute_request(qs))
107+
err = b"BBOX parameter cannot be combined with RULE" in r
108+
self.assertTrue(err)
109+
110110
def test_wms_GetLegendGraphic_LayerTitleSpace(self):
111111
qs = "?" + "&".join(["%s=%s" % i for i in list({
112112
"MAP": urllib.parse.quote(self.projectPath),
@@ -155,7 +155,7 @@ def test_wms_GetLegendGraphic_ShowFeatureCount(self):
155155
r, h = self._result(self._execute_request(qs))
156156
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1))
157157

158-
def test_getLegendGraphics_layertitle(self):
158+
def test_wms_getLegendGraphics_layertitle(self):
159159
"""Test that does not return an exception but an image"""
160160

161161
print("TEST FONT FAMILY: ", self.fontFamily)
@@ -196,7 +196,7 @@ def test_getLegendGraphics_layertitle(self):
196196
r, h = self._result(self._execute_request(qs))
197197
self._img_diff_error(r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15))
198198

199-
def test_getLegendGraphics_rulelabel(self):
199+
def test_wms_getLegendGraphics_rulelabel(self):
200200
"""Test that does not return an exception but an image"""
201201
parms = {
202202
'MAP': self.testdata_path + "test_project.qgs",
@@ -236,7 +236,7 @@ def test_getLegendGraphics_rulelabel(self):
236236
r, h = self._result(self._execute_request(qs))
237237
self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15))
238238

239-
def test_getLegendGraphics_rule(self):
239+
def test_wms_getLegendGraphics_rule(self):
240240
"""Test that does not return an exception but an image"""
241241
parms = {
242242
'MAP': self.testdata_path + "test_project_legend_rule.qgs",
@@ -691,6 +691,121 @@ def test_wms_GetLegendGraphic_ScaleSymbol_Max(self):
691691
r, h = self._result(self._execute_request(qs))
692692
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15))
693693

694+
def test_wms_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter(self):
695+
# map units per mm on 1:20000000 with SRCHEIGHT=598&SRCWIDTH=1640&BBOX=16.5,-69.7,73.3,86.1 would be around what is set as default: 0.359 map units per mm
696+
qs = "?" + "&".join(["%s=%s" % i for i in list({
697+
"MAP": self.testdata_path + 'test_project_scaledsymbols.qgs',
698+
"SERVICE": "WMS",
699+
"REQUEST": "GetLegendGraphic",
700+
"LAYER": "testlayer",
701+
"FORMAT": "image/png",
702+
"CRS": "EPSG:4326"
703+
}.items())])
704+
705+
r, h = self._result(self._execute_request(qs))
706+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter", max_size_diff=QSize(15, 15))
707+
708+
def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_2056(self):
709+
# 1:1000 scale on an EPSG:2056 calculating DPI that is around 96
710+
qs = "?" + "&".join(["%s=%s" % i for i in list({
711+
"MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs',
712+
"SERVICE": "WMS",
713+
"REQUEST": "GetLegendGraphic",
714+
"LAYER": "testlayer_2056",
715+
"FORMAT": "image/png",
716+
"SRCHEIGHT": "600",
717+
"SRCWIDTH": "1500",
718+
"BBOX": "2662610.7,1268841.8,2663010.5,1269000.05",
719+
"CRS": "EPSG:2056"
720+
}.items())])
721+
722+
r, h = self._result(self._execute_request(qs))
723+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_2056", max_size_diff=QSize(15, 15))
724+
725+
def test_wms_GetLegendGraphic_ScaleSymbol_DefaultScale_2056(self):
726+
# 1:1000 as default value - it's not exactly the same result than passing the bbox and size because of exact DPI 96 (default)
727+
qs = "?" + "&".join(["%s=%s" % i for i in list({
728+
"MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs',
729+
"SERVICE": "WMS",
730+
"REQUEST": "GetLegendGraphic",
731+
"LAYER": "testlayer_2056",
732+
"FORMAT": "image/png",
733+
"CRS": "EPSG:2056"
734+
}.items())])
735+
736+
r, h = self._result(self._execute_request(qs))
737+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultScale_2056", max_size_diff=QSize(15, 15))
738+
739+
def test_wms_GetLegendGraphic_LAYERFONTCOLOR(self):
740+
qs = "?" + "&".join(["%s=%s" % i for i in list({
741+
"MAP": urllib.parse.quote(self.projectPath),
742+
"SERVICE": "WMS",
743+
"VERSION": "1.1.1",
744+
"REQUEST": "GetLegendGraphic",
745+
"LAYER": "Country,Hello",
746+
"FORMAT": "image/png",
747+
"HEIGHT": "500",
748+
"WIDTH": "500",
749+
"CRS": "EPSG:3857",
750+
"LAYERFONTCOLOR": "red"
751+
}.items())])
752+
753+
r, h = self._result(self._execute_request(qs))
754+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
755+
756+
def test_wms_GetLegendGraphic_ITEMFONTCOLOR(self):
757+
qs = "?" + "&".join(["%s=%s" % i for i in list({
758+
"MAP": urllib.parse.quote(self.projectPath),
759+
"SERVICE": "WMS",
760+
"VERSION": "1.1.1",
761+
"REQUEST": "GetLegendGraphic",
762+
"LAYER": "Country,Hello",
763+
"FORMAT": "image/png",
764+
"HEIGHT": "500",
765+
"WIDTH": "500",
766+
"CRS": "EPSG:3857",
767+
"ITEMFONTCOLOR": "red",
768+
}.items())])
769+
770+
r, h = self._result(self._execute_request(qs))
771+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR", max_size_diff=QSize(10, 2))
772+
773+
def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR(self):
774+
qs = "?" + "&".join(["%s=%s" % i for i in list({
775+
"MAP": urllib.parse.quote(self.projectPath),
776+
"SERVICE": "WMS",
777+
"VERSION": "1.1.1",
778+
"REQUEST": "GetLegendGraphic",
779+
"LAYER": "Country,Hello",
780+
"FORMAT": "image/png",
781+
"HEIGHT": "500",
782+
"WIDTH": "500",
783+
"CRS": "EPSG:3857",
784+
"ITEMFONTCOLOR": "red",
785+
"LAYERFONTCOLOR": "blue"
786+
}.items())])
787+
788+
r, h = self._result(self._execute_request(qs))
789+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
790+
791+
def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_hex(self):
792+
qs = "?" + "&".join(["%s=%s" % i for i in list({
793+
"MAP": urllib.parse.quote(self.projectPath),
794+
"SERVICE": "WMS",
795+
"VERSION": "1.1.1",
796+
"REQUEST": "GetLegendGraphic",
797+
"LAYER": "Country,Hello",
798+
"FORMAT": "image/png",
799+
"HEIGHT": "500",
800+
"WIDTH": "500",
801+
"CRS": "EPSG:3857",
802+
"ITEMFONTCOLOR": r"%23FF0000",
803+
"LAYERFONTCOLOR": r"%230000FF"
804+
}.items())])
805+
806+
r, h = self._result(self._execute_request(qs))
807+
self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2))
808+
694809

695810
if __name__ == '__main__':
696811
unittest.main()
Binary file not shown.

0 commit comments

Comments
 (0)