From 727ca04353d40998df806422709c55aa55f9ea2a Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 17 Feb 2025 14:46:12 +1000 Subject: [PATCH 1/4] Fix data-defined overrides ignored in legend text format Fixes #60628 --- python/PyQt6/core/auto_generated/qgslegendsettings.sip.in | 8 ++++++++ python/PyQt6/core/auto_generated/qgslegendstyle.sip.in | 8 ++++++++ python/core/auto_generated/qgslegendsettings.sip.in | 8 ++++++++ python/core/auto_generated/qgslegendstyle.sip.in | 8 ++++++++ src/core/qgslegendrenderer.cpp | 2 ++ src/core/qgslegendsettings.cpp | 8 ++++++++ src/core/qgslegendsettings.h | 8 ++++++++ src/core/qgslegendstyle.cpp | 8 ++++++++ src/core/qgslegendstyle.h | 8 ++++++++ 9 files changed, 66 insertions(+) diff --git a/python/PyQt6/core/auto_generated/qgslegendsettings.sip.in b/python/PyQt6/core/auto_generated/qgslegendsettings.sip.in index ff12adefce32..ba3fff2e2871 100644 --- a/python/PyQt6/core/auto_generated/qgslegendsettings.sip.in +++ b/python/PyQt6/core/auto_generated/qgslegendsettings.sip.in @@ -26,6 +26,14 @@ The content of the legend is driven by the :py:class:`QgsLegendModel` class. public: QgsLegendSettings(); + void updateDataDefinedProperties( QgsRenderContext &context ); +%Docstring +Updates any data-defined properties in the settings, using the specified +render ``context``. + +.. versionadded:: 3.42 +%End + void setTitle( const QString &t ); %Docstring Sets the title for the legend, which will be rendered above all legend items. diff --git a/python/PyQt6/core/auto_generated/qgslegendstyle.sip.in b/python/PyQt6/core/auto_generated/qgslegendstyle.sip.in index d9227a117ed4..fade62db28d7 100644 --- a/python/PyQt6/core/auto_generated/qgslegendstyle.sip.in +++ b/python/PyQt6/core/auto_generated/qgslegendstyle.sip.in @@ -161,6 +161,14 @@ Writes the component's style definition to an XML element. Reads the component's style definition from an XML element. .. seealso:: :py:func:`writeXml` +%End + + void updateDataDefinedProperties( QgsRenderContext &context ); +%Docstring +Updates any data-defined properties in the style, using the specified +render ``context``. + +.. versionadded:: 3.42 %End static QString styleName( Style s ); diff --git a/python/core/auto_generated/qgslegendsettings.sip.in b/python/core/auto_generated/qgslegendsettings.sip.in index ff12adefce32..ba3fff2e2871 100644 --- a/python/core/auto_generated/qgslegendsettings.sip.in +++ b/python/core/auto_generated/qgslegendsettings.sip.in @@ -26,6 +26,14 @@ The content of the legend is driven by the :py:class:`QgsLegendModel` class. public: QgsLegendSettings(); + void updateDataDefinedProperties( QgsRenderContext &context ); +%Docstring +Updates any data-defined properties in the settings, using the specified +render ``context``. + +.. versionadded:: 3.42 +%End + void setTitle( const QString &t ); %Docstring Sets the title for the legend, which will be rendered above all legend items. diff --git a/python/core/auto_generated/qgslegendstyle.sip.in b/python/core/auto_generated/qgslegendstyle.sip.in index 39441c2e664e..3f569c89ddf9 100644 --- a/python/core/auto_generated/qgslegendstyle.sip.in +++ b/python/core/auto_generated/qgslegendstyle.sip.in @@ -161,6 +161,14 @@ Writes the component's style definition to an XML element. Reads the component's style definition from an XML element. .. seealso:: :py:func:`writeXml` +%End + + void updateDataDefinedProperties( QgsRenderContext &context ); +%Docstring +Updates any data-defined properties in the style, using the specified +render ``context``. + +.. versionadded:: 3.42 %End static QString styleName( Style s ); diff --git a/src/core/qgslegendrenderer.cpp b/src/core/qgslegendrenderer.cpp index f0701ea2910d..4f5d74ac7b1c 100644 --- a/src/core/qgslegendrenderer.cpp +++ b/src/core/qgslegendrenderer.cpp @@ -206,6 +206,8 @@ QSizeF QgsLegendRenderer::paintAndDetermineSize( QgsRenderContext &context ) if ( !rootGroup ) return size; + mSettings.updateDataDefinedProperties( context ); + // temporarily remove painter from context -- we don't need to actually draw anything yet. But we DO need // to send the full render context so that an expression context is available during the size calculation QgsScopedRenderContextPainterSwap noPainter( context, nullptr ); diff --git a/src/core/qgslegendsettings.cpp b/src/core/qgslegendsettings.cpp index 258ed06d91ca..85aca0a578c4 100644 --- a/src/core/qgslegendsettings.cpp +++ b/src/core/qgslegendsettings.cpp @@ -64,6 +64,14 @@ QgsLegendSettings::QgsLegendSettings() rstyle( QgsLegendStyle::SymbolLabel ).setTextFormat( f ); } +void QgsLegendSettings::updateDataDefinedProperties( QgsRenderContext &context ) +{ + rstyle( QgsLegendStyle::Title ).updateDataDefinedProperties( context ); + rstyle( QgsLegendStyle::Group ).updateDataDefinedProperties( context ); + rstyle( QgsLegendStyle::Subgroup ).updateDataDefinedProperties( context ); + rstyle( QgsLegendStyle::SymbolLabel ).updateDataDefinedProperties( context ); +} + QColor QgsLegendSettings::fontColor() const { return style( QgsLegendStyle::SymbolLabel ).textFormat().color(); diff --git a/src/core/qgslegendsettings.h b/src/core/qgslegendsettings.h index dec88dfe08eb..a516f73accd2 100644 --- a/src/core/qgslegendsettings.h +++ b/src/core/qgslegendsettings.h @@ -39,6 +39,14 @@ class CORE_EXPORT QgsLegendSettings public: QgsLegendSettings(); + /** + * Updates any data-defined properties in the settings, using the specified + * render \a context. + * + * \since QGIS 3.42 + */ + void updateDataDefinedProperties( QgsRenderContext &context ); + /** * Sets the title for the legend, which will be rendered above all legend items. * diff --git a/src/core/qgslegendstyle.cpp b/src/core/qgslegendstyle.cpp index 7c0391e23ae1..267a076c0a87 100644 --- a/src/core/qgslegendstyle.cpp +++ b/src/core/qgslegendstyle.cpp @@ -19,6 +19,7 @@ #include "qgsfontutils.h" #include "qgis.h" #include "qgsreadwritecontext.h" +#include "qgspropertycollection.h" #include #include @@ -110,6 +111,13 @@ void QgsLegendStyle::readXml( const QDomElement &elem, const QDomDocument &doc, mIndent = elem.attribute( QStringLiteral( "indent" ), QStringLiteral( "0" ) ).toDouble(); } +void QgsLegendStyle::updateDataDefinedProperties( QgsRenderContext &context ) +{ + if ( mTextFormat.dataDefinedProperties().hasActiveProperties() ) // note, we use format instead of tmpFormat here, it's const and potentially avoids a detach + mTextFormat.updateDataDefinedProperties( context ); + +} + QString QgsLegendStyle::styleName( Style s ) { switch ( s ) diff --git a/src/core/qgslegendstyle.h b/src/core/qgslegendstyle.h index 565fbd291e7c..8c3fe9cb5d78 100644 --- a/src/core/qgslegendstyle.h +++ b/src/core/qgslegendstyle.h @@ -165,6 +165,14 @@ class CORE_EXPORT QgsLegendStyle */ void readXml( const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ); + /** + * Updates any data-defined properties in the style, using the specified + * render \a context. + * + * \since QGIS 3.42 + */ + void updateDataDefinedProperties( QgsRenderContext &context ); + /** * Returns the name for a style component as a string. * From b7ee3add2ae7777cdcd718af2e071dbd3b6eeda3 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 18 Feb 2025 10:54:23 +1000 Subject: [PATCH 2/4] Add tests for QgsLegendSettings, QgsLegendStyle --- tests/src/python/CMakeLists.txt | 2 + tests/src/python/test_qgslegendsettings.py | 188 +++++++++++++++++++++ tests/src/python/test_qgslegendstyle.py | 147 ++++++++++++++++ 3 files changed, 337 insertions(+) create mode 100644 tests/src/python/test_qgslegendsettings.py create mode 100644 tests/src/python/test_qgslegendstyle.py diff --git a/tests/src/python/CMakeLists.txt b/tests/src/python/CMakeLists.txt index 328a827c26eb..fcc278110cc1 100644 --- a/tests/src/python/CMakeLists.txt +++ b/tests/src/python/CMakeLists.txt @@ -161,6 +161,8 @@ ADD_PYTHON_TEST(PyQgsLayoutSnapper test_qgslayoutsnapper.py) ADD_PYTHON_TEST(PyQgsLayoutTable test_qgslayouttable.py) ADD_PYTHON_TEST(PyQgsLegendPatchShape test_qgslegendpatchshape.py) ADD_PYTHON_TEST(PyQgsLegendRenderer test_qgslegendrenderer.py) +ADD_PYTHON_TEST(PyQgsLegendSettings test_qgslegendsettings.py) +ADD_PYTHON_TEST(PyQgsLegendStyle test_qgslegendstyle.py) ADD_PYTHON_TEST(PyQgsLinearReferencingSymbolLayer test_qgslinearreferencingsymbollayer.py) ADD_PYTHON_TEST(PyQgsLineSegment test_qgslinesegment.py) ADD_PYTHON_TEST(PyQgsLineString test_qgslinestring.py) diff --git a/tests/src/python/test_qgslegendsettings.py b/tests/src/python/test_qgslegendsettings.py new file mode 100644 index 000000000000..d314f7bf337e --- /dev/null +++ b/tests/src/python/test_qgslegendsettings.py @@ -0,0 +1,188 @@ +""""Test QgsLegendSettings + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +Run with ctest -V -R PyQgsLegendSettings + +""" + +from qgis.PyQt.QtCore import Qt, QSizeF +from qgis.PyQt.QtGui import QColor + +from qgis.core import ( + Qgis, + QgsLegendStyle, + QgsLegendSettings, + QgsExpressionContext, + QgsExpressionContextScope, + QgsTextFormat, + QgsRenderContext, + QgsPalLayerSettings, + QgsProperty, +) +import unittest +from qgis.testing import start_app, QgisTestCase + +from utilities import unitTestDataPath + +QGISAPP = start_app() +TEST_DATA_DIR = unitTestDataPath() + + +class TestPyQgsLegendSettings(QgisTestCase): + + def test_getters_setters(self): + settings = QgsLegendSettings() + + title = "Test Legend" + settings.setTitle(title) + self.assertEqual(settings.title(), title) + + settings.setTitleAlignment(Qt.AlignRight) + self.assertEqual(settings.titleAlignment(), Qt.AlignRight) + + test_style = QgsLegendStyle() + test_style.setIndent(33) + settings.setStyle(QgsLegendStyle.Style.Symbol, test_style) + self.assertEqual(settings.style(QgsLegendStyle.Style.Symbol).indent(), 33) + + test_style2 = QgsLegendStyle() + test_style2.setIndent(35) + settings.setStyle(QgsLegendStyle.Style.SymbolLabel, test_style2) + self.assertEqual(settings.style(QgsLegendStyle.Style.Symbol).indent(), 33) + self.assertEqual(settings.style(QgsLegendStyle.Style.SymbolLabel).indent(), 35) + + settings.setBoxSpace(5.0) + self.assertEqual(settings.boxSpace(), 5.0) + + settings.setWrapChar("\n") + self.assertEqual(settings.wrapChar(), "\n") + + settings.setColumnSpace(5.0) + self.assertEqual(settings.columnSpace(), 5.0) + + settings.setColumnCount(3) + self.assertEqual(settings.columnCount(), 3) + + settings.setSplitLayer(True) + self.assertTrue(settings.splitLayer()) + settings.setSplitLayer(False) + self.assertFalse(settings.splitLayer()) + + settings.setEqualColumnWidth(True) + self.assertTrue(settings.equalColumnWidth()) + settings.setEqualColumnWidth(False) + self.assertFalse(settings.equalColumnWidth()) + + settings.setSymbolSize(QSizeF(10.0, 10.0)) + self.assertEqual(settings.symbolSize(), QSizeF(10.0, 10.0)) + settings.setMaximumSymbolSize(20.0) + settings.setMinimumSymbolSize(5.0) + self.assertEqual(settings.maximumSymbolSize(), 20.0) + self.assertEqual(settings.minimumSymbolSize(), 5.0) + + settings.setSymbolAlignment(Qt.AlignRight) + self.assertEqual(settings.symbolAlignment(), Qt.AlignRight) + + settings.setDrawRasterStroke(True) + self.assertTrue(settings.drawRasterStroke()) + + settings.setRasterStrokeColor(QColor(255, 0, 0)) + self.assertEqual(settings.rasterStrokeColor(), QColor(255, 0, 0)) + + settings.setRasterStrokeWidth(2.0) + self.assertEqual(settings.rasterStrokeWidth(), 2.0) + + settings.setWmsLegendSize(QSizeF(50.0, 150.0)) + self.assertEqual(settings.wmsLegendSize(), QSizeF(50.0, 150.0)) + + settings.setSynchronousLegendRequests(True) + self.assertTrue(settings.synchronousLegendRequests()) + settings.setSynchronousLegendRequests(False) + self.assertFalse(settings.synchronousLegendRequests()) + + settings.setJsonRenderFlags(Qgis.LegendJsonRenderFlag.ShowRuleDetails) + self.assertEqual( + settings.jsonRenderFlags(), Qgis.LegendJsonRenderFlag.ShowRuleDetails + ) + + def test_split_string_for_wrapping(self): + settings = QgsLegendSettings() + settings.setWrapChar("|") + self.assertEqual( + settings.splitStringForWrapping("Test|String|Wrapping"), + ["Test", "String", "Wrapping"], + ) + + def test_evaluate_item_text(self): + settings = QgsLegendSettings() + settings.setWrapChar("|") + + expression_context_scope = QgsExpressionContextScope() + expression_context_scope.setVariable("test_string", "Test|String") + expression_context = QgsExpressionContext() + expression_context.appendScope(expression_context_scope) + + self.assertEqual( + settings.evaluateItemText( + "[% @test_string %]|Wrapping", expression_context + ), + ["Test", "String", "Wrapping"], + ) + + def test_update_data_defined_properties(self): + style = QgsLegendStyle() + text_format = QgsTextFormat() + text_format.setColor(QColor(255, 0, 0, 255)) + text_format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, + QgsProperty.fromExpression("@text_color"), + ) + style.setTextFormat(text_format) + settings = QgsLegendSettings() + settings.setStyle(QgsLegendStyle.Style.Group, style) + + style2 = QgsLegendStyle() + text_format = QgsTextFormat() + text_format.setColor(QColor(255, 0, 255, 255)) + text_format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, + QgsProperty.fromExpression("@text_color2"), + ) + style2.setTextFormat(text_format) + settings.setStyle(QgsLegendStyle.Style.Subgroup, style2) + + self.assertEqual( + settings.style(QgsLegendStyle.Style.Group).textFormat().color(), + QColor(255, 0, 0, 255), + ) + self.assertEqual( + settings.style(QgsLegendStyle.Style.Subgroup).textFormat().color(), + QColor(255, 0, 255, 255), + ) + + # apply data defined properties + rc = QgsRenderContext() + expression_context_scope = QgsExpressionContextScope() + expression_context_scope.setVariable("text_color", "0,255,0") + expression_context_scope.setVariable("text_color2", "255,255,255") + expression_context = QgsExpressionContext() + expression_context.appendScope(expression_context_scope) + rc.setExpressionContext(expression_context) + settings.updateDataDefinedProperties(rc) + + self.assertEqual( + settings.style(QgsLegendStyle.Style.Group).textFormat().color(), + QColor(0, 255, 0, 255), + ) + self.assertEqual( + settings.style(QgsLegendStyle.Style.Subgroup).textFormat().color(), + QColor(255, 255, 255, 255), + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/src/python/test_qgslegendstyle.py b/tests/src/python/test_qgslegendstyle.py new file mode 100644 index 000000000000..50e9ec5c0b2d --- /dev/null +++ b/tests/src/python/test_qgslegendstyle.py @@ -0,0 +1,147 @@ +""""Test QgsLegendStyle + +.. note:: This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + +Run with ctest -V -R PyQgsLegendStyle + +""" + +from qgis.PyQt.QtCore import Qt +from qgis.PyQt.QtGui import QColor +from qgis.PyQt.QtXml import QDomDocument + +from qgis.core import ( + QgsLegendStyle, + QgsTextFormat, + QgsReadWriteContext, + QgsPalLayerSettings, + QgsProperty, + QgsRenderContext, + QgsExpressionContext, + QgsExpressionContextScope, +) +import unittest +from qgis.testing import start_app, QgisTestCase + +from utilities import unitTestDataPath + +QGISAPP = start_app() +TEST_DATA_DIR = unitTestDataPath() + + +class TestPyQgsLegendStyle(QgisTestCase): + + def test_getters_setters(self): + style = QgsLegendStyle() + style.setMargin(QgsLegendStyle.Side.Top, 1.5) + style.setMargin(QgsLegendStyle.Side.Right, 3.6) + style.setMargin(QgsLegendStyle.Side.Bottom, 4.2) + style.setMargin(QgsLegendStyle.Side.Left, 5.2) + self.assertEqual(style.margin(QgsLegendStyle.Side.Top), 1.5) + self.assertEqual(style.margin(QgsLegendStyle.Side.Right), 3.6) + self.assertEqual(style.margin(QgsLegendStyle.Side.Bottom), 4.2) + self.assertEqual(style.margin(QgsLegendStyle.Side.Left), 5.2) + + style.setAlignment(Qt.AlignmentFlag.AlignCenter) + self.assertEqual(style.alignment(), Qt.AlignCenter) + + style.setIndent(33) + self.assertEqual(style.indent(), 33) + + text_format = QgsTextFormat() + text_format.setColor(QColor(255, 0, 0, 0)) + style.setTextFormat(text_format) + + self.assertEqual(style.textFormat().color(), QColor(255, 0, 0, 0)) + + def test_write_read(self): + doc = QDomDocument("testdoc") + elem = doc.createElement("test") + + style = QgsLegendStyle() + style.setMargin(QgsLegendStyle.Side.Top, 1.5) + style.setMargin(QgsLegendStyle.Side.Right, 3.6) + style.setMargin(QgsLegendStyle.Side.Bottom, 4.2) + style.setMargin(QgsLegendStyle.Side.Left, 5.2) + style.setAlignment(Qt.AlignmentFlag.AlignCenter) + style.setIndent(33) + text_format = QgsTextFormat() + text_format.setColor(QColor(255, 0, 0, 0)) + style.setTextFormat(text_format) + + style.writeXml("style", elem, doc, QgsReadWriteContext()) + + style2 = QgsLegendStyle() + style2.readXml(elem.firstChildElement("style"), doc, QgsReadWriteContext()) + + self.assertEqual(style2.margin(QgsLegendStyle.Side.Top), 1.5) + self.assertEqual(style2.margin(QgsLegendStyle.Side.Right), 3.6) + self.assertEqual(style2.margin(QgsLegendStyle.Side.Bottom), 4.2) + self.assertEqual(style2.margin(QgsLegendStyle.Side.Left), 5.2) + self.assertEqual(style2.alignment(), Qt.AlignCenter) + self.assertEqual(style2.indent(), 33) + self.assertEqual(style2.textFormat().color(), QColor(255, 0, 0, 0)) + + def test_update_data_defined_properties(self): + style = QgsLegendStyle() + text_format = QgsTextFormat() + text_format.setColor(QColor(255, 0, 0, 255)) + text_format.dataDefinedProperties().setProperty( + QgsPalLayerSettings.Property.Color, + QgsProperty.fromExpression("@text_color"), + ) + style.setTextFormat(text_format) + self.assertEqual(style.textFormat().color(), QColor(255, 0, 0, 255)) + + # apply data defined properties + rc = QgsRenderContext() + expression_context_scope = QgsExpressionContextScope() + expression_context_scope.setVariable("text_color", "0,255,0") + expression_context = QgsExpressionContext() + expression_context.appendScope(expression_context_scope) + rc.setExpressionContext(expression_context) + style.updateDataDefinedProperties(rc) + + self.assertEqual(style.textFormat().color(), QColor(0, 255, 0, 255)) + + def test_style_name(self): + self.assertEqual( + QgsLegendStyle.styleName(QgsLegendStyle.Style.Hidden), "hidden" + ) + self.assertEqual( + QgsLegendStyle.styleFromName("hidden"), QgsLegendStyle.Style.Hidden + ) + self.assertEqual(QgsLegendStyle.styleName(QgsLegendStyle.Style.Title), "title") + self.assertEqual( + QgsLegendStyle.styleFromName("title"), QgsLegendStyle.Style.Title + ) + self.assertEqual(QgsLegendStyle.styleName(QgsLegendStyle.Style.Group), "group") + self.assertEqual( + QgsLegendStyle.styleFromName("group"), QgsLegendStyle.Style.Group + ) + self.assertEqual( + QgsLegendStyle.styleName(QgsLegendStyle.Style.Subgroup), "subgroup" + ) + self.assertEqual( + QgsLegendStyle.styleFromName("subgroup"), QgsLegendStyle.Style.Subgroup + ) + self.assertEqual( + QgsLegendStyle.styleName(QgsLegendStyle.Style.Symbol), "symbol" + ) + self.assertEqual( + QgsLegendStyle.styleFromName("symbol"), QgsLegendStyle.Style.Symbol + ) + self.assertEqual( + QgsLegendStyle.styleName(QgsLegendStyle.Style.SymbolLabel), "symbolLabel" + ) + self.assertEqual( + QgsLegendStyle.styleFromName("symbolLabel"), + QgsLegendStyle.Style.SymbolLabel, + ) + + +if __name__ == "__main__": + unittest.main() From bbf643427d06a7bec19819776895d13860d6b6d7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 18 Feb 2025 11:01:22 +1000 Subject: [PATCH 3/4] Add test for legend with data defined text format properties --- tests/src/core/testqgslegendrenderer.cpp | 41 ++++++++++++++++++ tests/src/python/test_qgslegendsettings.py | 4 +- tests/src/python/test_qgslegendstyle.py | 4 +- .../expected_data_defined_text_format.png | Bin 0 -> 12942 bytes ...expected_data_defined_text_format_mask.png | Bin 0 -> 12551 bytes 5 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format.png create mode 100644 tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format_mask.png diff --git a/tests/src/core/testqgslegendrenderer.cpp b/tests/src/core/testqgslegendrenderer.cpp index 7be0df036bb3..0b87e17145a3 100644 --- a/tests/src/core/testqgslegendrenderer.cpp +++ b/tests/src/core/testqgslegendrenderer.cpp @@ -108,6 +108,7 @@ class TestQgsLegendRenderer : public QgsTest void testLeftAlignTextRightAlignSymbol(); void testCenterAlignTextRightAlignSymbol(); void testRightAlignTextRightAlignSymbol(); + void testDataDefinedTextFormat(); void testGroupHeadingSpacing(); void testGroupIndentSetup(); @@ -739,6 +740,46 @@ void TestQgsLegendRenderer::testRightAlignTextRightAlignSymbol() QVERIFY( _verifyImage( res, QStringLiteral( "legend_two_cols_right_align_symbol_right_align_text" ) ) ); } +void TestQgsLegendRenderer::testDataDefinedTextFormat() +{ + QgsMarkerSymbol *sym = new QgsMarkerSymbol(); + sym->setColor( Qt::red ); + sym->setSize( sym->size() * 6 ); + QgsCategorizedSymbolRenderer *catRenderer = dynamic_cast( mVL3->renderer() ); + QVERIFY( catRenderer ); + catRenderer->updateCategorySymbol( 0, sym ); + + QgsLayerTreeModel legendModel( mRoot ); + QgsLegendSettings settings; + + setStandardTestFont( settings, QStringLiteral( "Bold" ) ); + QgsTextFormat format = settings.style( QgsLegendStyle::Group ).textFormat(); + format.dataDefinedProperties().setProperty( QgsPalLayerSettings::Property::Color, QgsProperty::fromExpression( "@text_color_group" ) ); + settings.rstyle( QgsLegendStyle::Group ).setTextFormat( format ); + + format = settings.style( QgsLegendStyle::Subgroup ).textFormat(); + format.dataDefinedProperties().setProperty( QgsPalLayerSettings::Property::Color, QgsProperty::fromExpression( "@text_color_subgroup" ) ); + settings.rstyle( QgsLegendStyle::Subgroup ).setTextFormat( format ); + + format = settings.style( QgsLegendStyle::SymbolLabel ).textFormat(); + format.dataDefinedProperties().setProperty( QgsPalLayerSettings::Property::Color, QgsProperty::fromExpression( "@text_color_symbol_label" ) ); + settings.rstyle( QgsLegendStyle::SymbolLabel ).setTextFormat( format ); + + QgsExpressionContext context; + QgsExpressionContextScope *scope = new QgsExpressionContextScope(); + scope->setVariable( QStringLiteral( "text_color_group" ), QStringLiteral( "255,0,0" ) ); + scope->setVariable( QStringLiteral( "text_color_subgroup" ), QStringLiteral( "0,255,255" ) ); + scope->setVariable( QStringLiteral( "text_color_symbol_label" ), QStringLiteral( "255,0,255" ) ); + context.appendScope( scope ); + + QgsRenderContext rc; + rc.setExpressionContext( context ); + settings.updateDataDefinedProperties( rc ); + + QImage res = renderLegend( &legendModel, settings ); + QVERIFY( _verifyImage( res, QStringLiteral( "data_defined_text_format" ) ) ); +} + void TestQgsLegendRenderer::testGroupHeadingSpacing() { QgsMarkerSymbol *sym = new QgsMarkerSymbol(); diff --git a/tests/src/python/test_qgslegendsettings.py b/tests/src/python/test_qgslegendsettings.py index d314f7bf337e..4f3965b4a1e0 100644 --- a/tests/src/python/test_qgslegendsettings.py +++ b/tests/src/python/test_qgslegendsettings.py @@ -41,8 +41,8 @@ def test_getters_setters(self): settings.setTitle(title) self.assertEqual(settings.title(), title) - settings.setTitleAlignment(Qt.AlignRight) - self.assertEqual(settings.titleAlignment(), Qt.AlignRight) + settings.setTitleAlignment(Qt.AlignmentFlag.AlignRight) + self.assertEqual(settings.titleAlignment(), Qt.AlignmentFlag.AlignRight) test_style = QgsLegendStyle() test_style.setIndent(33) diff --git a/tests/src/python/test_qgslegendstyle.py b/tests/src/python/test_qgslegendstyle.py index 50e9ec5c0b2d..2047de9067f5 100644 --- a/tests/src/python/test_qgslegendstyle.py +++ b/tests/src/python/test_qgslegendstyle.py @@ -46,7 +46,7 @@ def test_getters_setters(self): self.assertEqual(style.margin(QgsLegendStyle.Side.Left), 5.2) style.setAlignment(Qt.AlignmentFlag.AlignCenter) - self.assertEqual(style.alignment(), Qt.AlignCenter) + self.assertEqual(style.alignment(), Qt.AlignmentFlag.AlignCenter) style.setIndent(33) self.assertEqual(style.indent(), 33) @@ -81,7 +81,7 @@ def test_write_read(self): self.assertEqual(style2.margin(QgsLegendStyle.Side.Right), 3.6) self.assertEqual(style2.margin(QgsLegendStyle.Side.Bottom), 4.2) self.assertEqual(style2.margin(QgsLegendStyle.Side.Left), 5.2) - self.assertEqual(style2.alignment(), Qt.AlignCenter) + self.assertEqual(style2.alignment(), Qt.AlignmentFlag.AlignCenter) self.assertEqual(style2.indent(), 33) self.assertEqual(style2.textFormat().color(), QColor(255, 0, 0, 0)) diff --git a/tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format.png b/tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format.png new file mode 100644 index 0000000000000000000000000000000000000000..88490f79f09ca0e4ad1a20002e8a5c10f3ee3fbd GIT binary patch literal 12942 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 Yb7h?FTB`rw#Q>(ZC4;+IGYybcN literal 0 HcmV?d00001 diff --git a/tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format_mask.png b/tests/testdata/control_images/legend/expected_data_defined_text_format/expected_data_defined_text_format_mask.png new file mode 100644 index 0000000000000000000000000000000000000000..38ec2fbe901582693a9d8f3152ed26d44ed3a002 GIT binary patch literal 12551 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 literal 0 HcmV?d00001 From 700df806f38110791a83354750defe67bd72bf55 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 19 Feb 2025 10:12:31 +1000 Subject: [PATCH 4/4] Fix test --- tests/src/python/test_qgslegendsettings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/python/test_qgslegendsettings.py b/tests/src/python/test_qgslegendsettings.py index 4f3965b4a1e0..f1076b011273 100644 --- a/tests/src/python/test_qgslegendsettings.py +++ b/tests/src/python/test_qgslegendsettings.py @@ -84,8 +84,8 @@ def test_getters_setters(self): self.assertEqual(settings.maximumSymbolSize(), 20.0) self.assertEqual(settings.minimumSymbolSize(), 5.0) - settings.setSymbolAlignment(Qt.AlignRight) - self.assertEqual(settings.symbolAlignment(), Qt.AlignRight) + settings.setSymbolAlignment(Qt.AlignmentFlag.AlignRight) + self.assertEqual(settings.symbolAlignment(), Qt.AlignmentFlag.AlignRight) settings.setDrawRasterStroke(True) self.assertTrue(settings.drawRasterStroke())