diff --git a/python/core/auto_generated/qgslegendsettings.sip.in b/python/core/auto_generated/qgslegendsettings.sip.in index 97b4288798ae..de8574f6155f 100644 --- a/python/core/auto_generated/qgslegendsettings.sip.in +++ b/python/core/auto_generated/qgslegendsettings.sip.in @@ -75,6 +75,30 @@ Returns style QColor fontColor() const; void setFontColor( const QColor &c ); + QColor layerFontColor() const; +%Docstring +Returns layer font color, defaults to fontColor() + +.. seealso:: :py:func:`setLayerFontColor` + +.. seealso:: :py:func:`fontColor` + +.. versionadded:: 3.4.7 +%End + + void setLayerFontColor( const QColor &fontColor ); +%Docstring +Sets layer font color to ``fontColor`` +Overrides fontColor() + +.. seealso:: :py:func:`layerFontColor` + +.. seealso:: :py:func:`fontColor` + +.. versionadded:: 3.4.7 +%End + + QSizeF symbolSize() const; void setSymbolSize( QSizeF s ); diff --git a/src/core/qgslegendrenderer.cpp b/src/core/qgslegendrenderer.cpp index d23bdc04f4f0..81b9cd2d65f6 100644 --- a/src/core/qgslegendrenderer.cpp +++ b/src/core/qgslegendrenderer.cpp @@ -585,9 +585,9 @@ QSizeF QgsLegendRenderer::drawLayerTitleInternal( QgsLayerTreeLayer *nodeLayer, double y = point.y(); if ( context && context->painter() ) - context->painter()->setPen( mSettings.fontColor() ); + context->painter()->setPen( mSettings.layerFontColor() ); else if ( painter ) - painter->setPen( mSettings.fontColor() ); + painter->setPen( mSettings.layerFontColor() ); QFont layerFont = mSettings.style( nodeLegendStyle( nodeLayer ) ).font(); diff --git a/src/core/qgslegendsettings.h b/src/core/qgslegendsettings.h index 47f6efde2114..9cf4ca307b85 100644 --- a/src/core/qgslegendsettings.h +++ b/src/core/qgslegendsettings.h @@ -88,6 +88,24 @@ class CORE_EXPORT QgsLegendSettings QColor fontColor() const {return mFontColor;} void setFontColor( const QColor &c ) {mFontColor = c;} + /** + * Returns layer font color, defaults to fontColor() + * \see setLayerFontColor() + * \see fontColor() + * \since QGIS 3.4.7 + */ + QColor layerFontColor() const {return mLayerFontColor.isValid() ? mLayerFontColor : fontColor() ;} + + /** + * Sets layer font color to \a fontColor + * Overrides fontColor() + * \see layerFontColor() + * \see fontColor() + * \since QGIS 3.4.7 + */ + void setLayerFontColor( const QColor &fontColor ) {mLayerFontColor = fontColor;} + + QSizeF symbolSize() const {return mSymbolSize;} void setSymbolSize( QSizeF s ) {mSymbolSize = s;} @@ -306,6 +324,9 @@ class CORE_EXPORT QgsLegendSettings //! DPI to be used when rendering legend int mDpi = 96; + + //! Font color for layers, overrides font color + QColor mLayerFontColor; }; diff --git a/src/server/services/wms/qgswmsparameters.cpp b/src/server/services/wms/qgswmsparameters.cpp index e15386a6cf5e..3a1a92f8d87d 100644 --- a/src/server/services/wms/qgswmsparameters.cpp +++ b/src/server/services/wms/qgswmsparameters.cpp @@ -1099,6 +1099,16 @@ namespace QgsWms return mWmsParameters[ QgsWmsParameter::ITEMFONTSIZE ].toDouble(); } + QString QgsWmsParameters::itemFontColor() const + { + return mWmsParameters[ QgsWmsParameter::ITEMFONTCOLOR ].toString(); + } + + QColor QgsWmsParameters::itemFontColorAsColor() const + { + return mWmsParameters[ QgsWmsParameter::ITEMFONTCOLOR ].toColor(); + } + QFont QgsWmsParameters::layerFont() const { QFont font; @@ -1153,6 +1163,18 @@ namespace QgsWms settings.rstyle( QgsLegendStyle::Style::Subgroup ).setMargin( QgsLegendStyle::Side::Bottom, layerTitleSpaceAsDouble() ); settings.rstyle( QgsLegendStyle::Style::Subgroup ).setFont( layerFont() ); + if ( !itemFontColor().isEmpty() ) + { + settings.setFontColor( itemFontColorAsColor() ); + } + + // Ok, this is tricky: because QgsLegendSettings's layerFontColor was added to the API after + // fontColor, to fix regressions #21871 and #21870 and the previous behavior was to use fontColor + // for the whole legend we need to preserve that behavior. + // But, the 2.18 server parameters ITEMFONTCOLOR did not have effect on the layer titles too, so + // we set explicitly layerFontColor to black if it's not overridden by LAYERFONTCOLOR argument. + settings.setLayerFontColor( layerFontColor().isEmpty() ? QColor( Qt::black ) : layerFontColorAsColor() ); + settings.rstyle( QgsLegendStyle::Style::SymbolLabel ).setFont( itemFont() ); settings.rstyle( QgsLegendStyle::Style::Symbol ).setMargin( QgsLegendStyle::Side::Top, symbolSpaceAsDouble() ); settings.rstyle( QgsLegendStyle::Style::SymbolLabel ).setMargin( QgsLegendStyle::Side::Left, iconLabelSpaceAsDouble() ); diff --git a/src/server/services/wms/qgswmsparameters.h b/src/server/services/wms/qgswmsparameters.h index 07c0897213e0..49127ef27e0f 100644 --- a/src/server/services/wms/qgswmsparameters.h +++ b/src/server/services/wms/qgswmsparameters.h @@ -186,7 +186,7 @@ namespace QgsWms /** * Default destructor for QgsWmsParameter. */ - virtual ~QgsWmsParameter() = default; + virtual ~QgsWmsParameter() override = default; /** * Returns true if the parameter is valid, false otherwise. @@ -335,7 +335,7 @@ namespace QgsWms */ QgsWmsParameters(); - virtual ~QgsWmsParameters() = default; + virtual ~QgsWmsParameters() override = default; /** * Dumps parameters. diff --git a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py index 6b83c9ccf3ec..da8532606bc8 100644 --- a/tests/src/python/test_qgsserver_wms_getlegendgraphic.py +++ b/tests/src/python/test_qgsserver_wms_getlegendgraphic.py @@ -62,27 +62,6 @@ def test_getLegendGraphics(self): self.assertEqual(-1, h.find(b'Content-Type: text/xml; charset=utf-8'), "Header: %s\nResponse:\n%s" % (h, r)) self.assertNotEqual(-1, h.find(b'Content-Type: image/png'), "Header: %s\nResponse:\n%s" % (h, r)) - def test_getLegendGraphics_invalid_parameters(self): - """Test that does return an exception""" - qs = "?" + "&".join(["%s=%s" % i for i in list({ - "MAP": urllib.parse.quote(self.projectPath), - "SERVICE": "WMS", - "VERSION": "1.1.1", - "REQUEST": "GetLegendGraphic", - "LAYER": "Country,Hello,db_point", - "LAYERTITLE": "FALSE", - "FORMAT": "image/png", - "HEIGHT": "500", - "WIDTH": "500", - "RULE": "1", - "BBOX": "-151.7,-38.9,51.0,78.0", - "CRS": "EPSG:4326" - }.items())]) - - r, h = self._result(self._execute_request(qs)) - err = b"BBOX parameter cannot be combined with RULE" in r - self.assertTrue(err) - def test_wms_GetLegendGraphic_LayerSpace(self): qs = "?" + "&".join(["%s=%s" % i for i in list({ "MAP": urllib.parse.quote(self.projectPath), @@ -107,6 +86,27 @@ def test_wms_GetLegendGraphic_LayerSpace(self): r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_LayerSpace", max_size_diff=QSize(1, 1)) + def test_wms_getLegendGraphics_invalid_parameters(self): + """Test that does return an exception""" + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello,db_point", + "LAYERTITLE": "FALSE", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "RULE": "1", + "BBOX": "-151.7,-38.9,51.0,78.0", + "CRS": "EPSG:4326" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + err = b"BBOX parameter cannot be combined with RULE" in r + self.assertTrue(err) + def test_wms_GetLegendGraphic_LayerTitleSpace(self): qs = "?" + "&".join(["%s=%s" % i for i in list({ "MAP": urllib.parse.quote(self.projectPath), @@ -155,7 +155,7 @@ def test_wms_GetLegendGraphic_ShowFeatureCount(self): r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_ShowFeatureCount", max_size_diff=QSize(1, 1)) - def test_getLegendGraphics_layertitle(self): + def test_wms_getLegendGraphics_layertitle(self): """Test that does not return an exception but an image""" print("TEST FONT FAMILY: ", self.fontFamily) @@ -196,7 +196,7 @@ def test_getLegendGraphics_layertitle(self): r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_test_layertitle_false", 250, QSize(15, 15)) - def test_getLegendGraphics_rulelabel(self): + def test_wms_getLegendGraphics_rulelabel(self): """Test that does not return an exception but an image""" parms = { 'MAP': self.testdata_path + "test_project.qgs", @@ -236,7 +236,7 @@ def test_getLegendGraphics_rulelabel(self): r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_rulelabel_false", 250, QSize(15, 15)) - def test_getLegendGraphics_rule(self): + def test_wms_getLegendGraphics_rule(self): """Test that does not return an exception but an image""" parms = { 'MAP': self.testdata_path + "test_project_legend_rule.qgs", @@ -691,6 +691,121 @@ def test_wms_GetLegendGraphic_ScaleSymbol_Max(self): r, h = self._result(self._execute_request(qs)) self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Max", max_size_diff=QSize(15, 15)) + def test_wms_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter(self): + # 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 + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": self.testdata_path + 'test_project_scaledsymbols.qgs', + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer", + "FORMAT": "image/png", + "CRS": "EPSG:4326" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultMapUnitsPerMillimeter", max_size_diff=QSize(15, 15)) + + def test_wms_GetLegendGraphic_ScaleSymbol_Scaled_2056(self): + # 1:1000 scale on an EPSG:2056 calculating DPI that is around 96 + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs', + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "SRCHEIGHT": "600", + "SRCWIDTH": "1500", + "BBOX": "2662610.7,1268841.8,2663010.5,1269000.05", + "CRS": "EPSG:2056" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_Scaled_2056", max_size_diff=QSize(15, 15)) + + def test_wms_GetLegendGraphic_ScaleSymbol_DefaultScale_2056(self): + # 1:1000 as default value - it's not exactly the same result than passing the bbox and size because of exact DPI 96 (default) + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": self.testdata_path + 'test_project_scaledsymbols_2056.qgs', + "SERVICE": "WMS", + "REQUEST": "GetLegendGraphic", + "LAYER": "testlayer_2056", + "FORMAT": "image/png", + "CRS": "EPSG:2056" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ScaleSymbol_DefaultScale_2056", max_size_diff=QSize(15, 15)) + + def test_wms_GetLegendGraphic_LAYERFONTCOLOR(self): + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "LAYERFONTCOLOR": "red" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_LAYERFONTCOLOR", max_size_diff=QSize(10, 2)) + + def test_wms_GetLegendGraphic_ITEMFONTCOLOR(self): + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ITEMFONTCOLOR": "red", + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR", max_size_diff=QSize(10, 2)) + + def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR(self): + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ITEMFONTCOLOR": "red", + "LAYERFONTCOLOR": "blue" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2)) + + def test_wms_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_hex(self): + qs = "?" + "&".join(["%s=%s" % i for i in list({ + "MAP": urllib.parse.quote(self.projectPath), + "SERVICE": "WMS", + "VERSION": "1.1.1", + "REQUEST": "GetLegendGraphic", + "LAYER": "Country,Hello", + "FORMAT": "image/png", + "HEIGHT": "500", + "WIDTH": "500", + "CRS": "EPSG:3857", + "ITEMFONTCOLOR": r"%23FF0000", + "LAYERFONTCOLOR": r"%230000FF" + }.items())]) + + r, h = self._result(self._execute_request(qs)) + self._img_diff_error(r, h, "WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR", max_size_diff=QSize(10, 2)) + if __name__ == '__main__': unittest.main() diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR.png new file mode 100644 index 000000000000..1b6b6038f9dc Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_mask.png new file mode 100644 index 000000000000..a9e0fb83af1e Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR.png new file mode 100644 index 000000000000..1b6b6038f9dc Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_mask.png new file mode 100644 index 000000000000..108bd3237265 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR/WMS_GetLegendGraphic_ITEMFONTCOLOR_and_LAYERFONTCOLOR_mask.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR.png new file mode 100644 index 000000000000..3cd4d6bc0c5f Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR.png differ diff --git a/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR_mask.png b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR_mask.png new file mode 100644 index 000000000000..108bd3237265 Binary files /dev/null and b/tests/testdata/control_images/qgis_server/WMS_GetLegendGraphic_LAYERFONTCOLOR/WMS_GetLegendGraphic_LAYERFONTCOLOR_mask.png differ diff --git a/tests/testdata/qgis_server_accesscontrol/geo.gpkg b/tests/testdata/qgis_server_accesscontrol/geo.gpkg index 9aacd62f9f5d..da2787c98124 100644 Binary files a/tests/testdata/qgis_server_accesscontrol/geo.gpkg and b/tests/testdata/qgis_server_accesscontrol/geo.gpkg differ