diff --git a/python/PyQt6/core/auto_additions/qgsstackeddiagram.py b/python/PyQt6/core/auto_additions/qgsstackeddiagram.py index 350b840310ed..4d3fc2a8efa2 100644 --- a/python/PyQt6/core/auto_additions/qgsstackeddiagram.py +++ b/python/PyQt6/core/auto_additions/qgsstackeddiagram.py @@ -3,7 +3,3 @@ QgsStackedDiagram.__group__ = ['diagram'] except NameError: pass -try: - QgsStackedDiagram.DiagramData.__group__ = ['diagram'] -except NameError: - pass diff --git a/python/PyQt6/core/auto_generated/diagram/qgsstackeddiagram.sip.in b/python/PyQt6/core/auto_generated/diagram/qgsstackeddiagram.sip.in index 33c107d8aea2..d8d7860ca213 100644 --- a/python/PyQt6/core/auto_generated/diagram/qgsstackeddiagram.sip.in +++ b/python/PyQt6/core/auto_generated/diagram/qgsstackeddiagram.sip.in @@ -25,55 +25,11 @@ A diagram composed of several subdiagrams, located side by side. %End public: - struct DiagramData - { - QgsDiagram *diagram; - QgsDiagramSettings *settings; - }; - QgsStackedDiagram(); virtual QgsStackedDiagram *clone() const /Factory/; - void addSubDiagram( QgsDiagram *diagram, QgsDiagramSettings *s ); -%Docstring -Adds a subdiagram to the stacked diagram object along with its corresponding settings. - -:param diagram: subdiagram to be added to the stacked diagram -:param s: subdiagram settings - Subdiagrams added first will appear more to the left (if stacked diagram is horizontal), - or more to the top (if stacked diagram is vertical). -%End - - int subDiagramCount() const; -%Docstring -Returns the number of subdiagrams that this stacked diagram is composed of. -%End - - QString subDiagramType( int index ) const; -%Docstring -Returns the type of the subdiagram located at a given ``index``. -%End - - QList< QgsDiagram * > subDiagrams( const QgsDiagramSettings &s ) const; -%Docstring -Returns an ordered list with the subdiagrams of the stacked diagram object. -If the stacked diagram orientation is vertical, the list is returned backwards. - -:param s: stacked diagram settings -%End - - QgsDiagramSettings *subDiagramSettings( const QgsDiagram *diagram ) const; -%Docstring -Returns the settings associated to the ``diagram``. -%End - - QgsDiagramSettings *subDiagramSettings( int index ) const; -%Docstring -Returns the diagram settings for the diagram located at a given ``index``. -%End - void subDiagramPosition( QPointF &newPos, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramSettings &subSettings ); %Docstring Calculates the position for the next subdiagram, updating the ``newPos`` object. diff --git a/python/PyQt6/core/auto_generated/qgsdiagramrenderer.sip.in b/python/PyQt6/core/auto_generated/qgsdiagramrenderer.sip.in index e198ba6a7cba..0186aa3cf9f7 100644 --- a/python/PyQt6/core/auto_generated/qgsdiagramrenderer.sip.in +++ b/python/PyQt6/core/auto_generated/qgsdiagramrenderer.sip.in @@ -680,6 +680,8 @@ Evaluates and returns the diagram settings relating to a diagram for a specific sipType = sipType_QgsSingleCategoryDiagramRenderer; else if ( sipCpp->rendererName() == QLatin1String( "LinearlyInterpolated" ) ) sipType = sipType_QgsLinearlyInterpolatedDiagramRenderer; + else if ( sipCpp->rendererName() == QLatin1String( "Stacked" ) ) + sipType = sipType_QgsStackedDiagramRenderer; else sipType = NULL; %End @@ -712,7 +714,7 @@ Returns the set of any fields required for diagram rendering :param context: expression context the diagrams will be drawn using %End - void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; %Docstring Renders the diagram for a specified feature at a specific position in the passed render context. %End @@ -769,23 +771,21 @@ Sets whether the renderer will show legend items for diagram attributes. protected: QgsDiagramRenderer( const QgsDiagramRenderer &other ); - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const = 0; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const = 0; %Docstring Returns diagram settings for a feature (or ``False`` if the diagram for the feature is not to be rendered). Used internally within :py:func:`~QgsDiagramRenderer.renderDiagram` :param feature: the feature :param c: render context :param s: out: diagram settings for the feature -:param subDiagram: subDiagram object for stacked diagram case %End - virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const = 0; + virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const = 0; %Docstring Returns size of the diagram (in painter units) or an invalid size in case of error :param feature: the feature :param c: render context -:param subDiagram: subDiagram object for stacked diagram case %End void convertSizeToMapUnits( QSizeF &size, const QgsRenderContext &context ) const; @@ -804,13 +804,6 @@ Returns the paint device dpi (or -1 in case of error Reads internal QgsDiagramRenderer state from a DOM element. .. seealso:: _writeXml -%End - - void _readXmlSubdiagrams( const QDomElement &elem, const QgsReadWriteContext &context ); -%Docstring -Reads Stacked Diagram's subdiagram state from a DOM element. - -.. seealso:: _writeXmlSubDiagrams %End void _writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; @@ -820,12 +813,6 @@ Writes internal QgsDiagramRenderer diagram state to a DOM element. .. seealso:: _readXml %End - void _writeXmlSubDiagrams( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; -%Docstring -Writes Stacked Diagram's subdiagram state to a DOM element. - -.. seealso:: _readXmlSubdiagrams -%End }; @@ -864,10 +851,10 @@ Renders the diagrams for all features with the same settings protected: - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; - virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const; + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; }; @@ -957,14 +944,115 @@ Returns configuration of appearance of legend. Will return ``None`` if no config %End protected: - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; + + + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; + + +}; + +class QgsStackedDiagramRenderer : QgsDiagramRenderer +{ +%Docstring(signature="appended") +Renders diagrams using mixed diagram render types. The size of +the rendered diagram is given by a combination of subrenderers. + +.. versionadded:: 3.40 +%End + +%TypeHeaderCode +#include "qgsdiagramrenderer.h" +%End + public: + QgsStackedDiagramRenderer(); + + virtual QgsStackedDiagramRenderer *clone() const /Factory/; + + + virtual QSizeF sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const; +%Docstring +Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error +%End + + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; +%Docstring +Renders the diagram for a specified feature at a specific position in the +passed render context, taking all renderers and their own diagrams into account. +Diagram rendering is delegated to renderer's diagram. +%End + + virtual QList diagramSettings() const; + +%Docstring +Returns list with all diagram settings in the renderer +%End + void setDiagramSettings( const QgsDiagramSettings &s ); + + virtual QList diagramAttributes() const; + + + + virtual QString rendererName() const; + + virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context ); + + virtual void writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; + + + void _readXmlSubRenderers( const QDomElement &elem, const QgsReadWriteContext &context ); +%Docstring +Reads stacked renderers state from a DOM element. + +.. seealso:: _writeXmlSubRenderers +%End - virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const; + void _writeXmlSubRenderers( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; +%Docstring +Writes stacked renderers state to a DOM element. + +.. seealso:: _readXmlSubRenderers +%End + + virtual QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const /Factory/; + + + QList< QgsDiagramRenderer * > renderers() const; +%Docstring +Returns an ordered list with the renderers of the stacked renderer object. +If the stacked diagram orientation is vertical, the list is returned backwards. +%End + + void addRenderer( QgsDiagramRenderer *renderer ); +%Docstring +Adds a renderer to the stacked renderer object. + +:param renderer: diagram renderer to be added to the stacked renderer + Renderers added first will render their diagrams first, i.e., more to + the left (horizontal mode) or more to the top (vertical mode). +%End + + const QgsDiagramRenderer *renderer( const int index ) const; +%Docstring +Returns the renderer at the given ``index``. +@param index index of the disired renderer in the stacked renderer +%End + + int rendererCount() const; +%Docstring +Returns the number of renderers that this stacked renderer is composed of. +%End + + protected: + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; + + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; }; + /************************************************************************ * This file has been generated automatically from * * * diff --git a/python/core/auto_additions/qgsstackeddiagram.py b/python/core/auto_additions/qgsstackeddiagram.py index 350b840310ed..4d3fc2a8efa2 100644 --- a/python/core/auto_additions/qgsstackeddiagram.py +++ b/python/core/auto_additions/qgsstackeddiagram.py @@ -3,7 +3,3 @@ QgsStackedDiagram.__group__ = ['diagram'] except NameError: pass -try: - QgsStackedDiagram.DiagramData.__group__ = ['diagram'] -except NameError: - pass diff --git a/python/core/auto_generated/diagram/qgsstackeddiagram.sip.in b/python/core/auto_generated/diagram/qgsstackeddiagram.sip.in index 33c107d8aea2..d8d7860ca213 100644 --- a/python/core/auto_generated/diagram/qgsstackeddiagram.sip.in +++ b/python/core/auto_generated/diagram/qgsstackeddiagram.sip.in @@ -25,55 +25,11 @@ A diagram composed of several subdiagrams, located side by side. %End public: - struct DiagramData - { - QgsDiagram *diagram; - QgsDiagramSettings *settings; - }; - QgsStackedDiagram(); virtual QgsStackedDiagram *clone() const /Factory/; - void addSubDiagram( QgsDiagram *diagram, QgsDiagramSettings *s ); -%Docstring -Adds a subdiagram to the stacked diagram object along with its corresponding settings. - -:param diagram: subdiagram to be added to the stacked diagram -:param s: subdiagram settings - Subdiagrams added first will appear more to the left (if stacked diagram is horizontal), - or more to the top (if stacked diagram is vertical). -%End - - int subDiagramCount() const; -%Docstring -Returns the number of subdiagrams that this stacked diagram is composed of. -%End - - QString subDiagramType( int index ) const; -%Docstring -Returns the type of the subdiagram located at a given ``index``. -%End - - QList< QgsDiagram * > subDiagrams( const QgsDiagramSettings &s ) const; -%Docstring -Returns an ordered list with the subdiagrams of the stacked diagram object. -If the stacked diagram orientation is vertical, the list is returned backwards. - -:param s: stacked diagram settings -%End - - QgsDiagramSettings *subDiagramSettings( const QgsDiagram *diagram ) const; -%Docstring -Returns the settings associated to the ``diagram``. -%End - - QgsDiagramSettings *subDiagramSettings( int index ) const; -%Docstring -Returns the diagram settings for the diagram located at a given ``index``. -%End - void subDiagramPosition( QPointF &newPos, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramSettings &subSettings ); %Docstring Calculates the position for the next subdiagram, updating the ``newPos`` object. diff --git a/python/core/auto_generated/qgsdiagramrenderer.sip.in b/python/core/auto_generated/qgsdiagramrenderer.sip.in index 2abf1b0c6d01..b946b658e4f2 100644 --- a/python/core/auto_generated/qgsdiagramrenderer.sip.in +++ b/python/core/auto_generated/qgsdiagramrenderer.sip.in @@ -680,6 +680,8 @@ Evaluates and returns the diagram settings relating to a diagram for a specific sipType = sipType_QgsSingleCategoryDiagramRenderer; else if ( sipCpp->rendererName() == QLatin1String( "LinearlyInterpolated" ) ) sipType = sipType_QgsLinearlyInterpolatedDiagramRenderer; + else if ( sipCpp->rendererName() == QLatin1String( "Stacked" ) ) + sipType = sipType_QgsStackedDiagramRenderer; else sipType = NULL; %End @@ -712,7 +714,7 @@ Returns the set of any fields required for diagram rendering :param context: expression context the diagrams will be drawn using %End - void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; %Docstring Renders the diagram for a specified feature at a specific position in the passed render context. %End @@ -769,23 +771,21 @@ Sets whether the renderer will show legend items for diagram attributes. protected: QgsDiagramRenderer( const QgsDiagramRenderer &other ); - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const = 0; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const = 0; %Docstring Returns diagram settings for a feature (or ``False`` if the diagram for the feature is not to be rendered). Used internally within :py:func:`~QgsDiagramRenderer.renderDiagram` :param feature: the feature :param c: render context :param s: out: diagram settings for the feature -:param subDiagram: subDiagram object for stacked diagram case %End - virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const = 0; + virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const = 0; %Docstring Returns size of the diagram (in painter units) or an invalid size in case of error :param feature: the feature :param c: render context -:param subDiagram: subDiagram object for stacked diagram case %End void convertSizeToMapUnits( QSizeF &size, const QgsRenderContext &context ) const; @@ -804,13 +804,6 @@ Returns the paint device dpi (or -1 in case of error Reads internal QgsDiagramRenderer state from a DOM element. .. seealso:: _writeXml -%End - - void _readXmlSubdiagrams( const QDomElement &elem, const QgsReadWriteContext &context ); -%Docstring -Reads Stacked Diagram's subdiagram state from a DOM element. - -.. seealso:: _writeXmlSubDiagrams %End void _writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; @@ -820,12 +813,6 @@ Writes internal QgsDiagramRenderer diagram state to a DOM element. .. seealso:: _readXml %End - void _writeXmlSubDiagrams( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; -%Docstring -Writes Stacked Diagram's subdiagram state to a DOM element. - -.. seealso:: _readXmlSubdiagrams -%End }; @@ -864,10 +851,10 @@ Renders the diagrams for all features with the same settings protected: - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; - virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const; + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; }; @@ -957,14 +944,115 @@ Returns configuration of appearance of legend. Will return ``None`` if no config %End protected: - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = 0 ) const; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; + + + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; + + +}; + +class QgsStackedDiagramRenderer : QgsDiagramRenderer +{ +%Docstring(signature="appended") +Renders diagrams using mixed diagram render types. The size of +the rendered diagram is given by a combination of subrenderers. + +.. versionadded:: 3.40 +%End + +%TypeHeaderCode +#include "qgsdiagramrenderer.h" +%End + public: + QgsStackedDiagramRenderer(); + + virtual QgsStackedDiagramRenderer *clone() const /Factory/; + + + virtual QSizeF sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const; +%Docstring +Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error +%End + + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; +%Docstring +Renders the diagram for a specified feature at a specific position in the +passed render context, taking all renderers and their own diagrams into account. +Diagram rendering is delegated to renderer's diagram. +%End + + virtual QList diagramSettings() const; + +%Docstring +Returns list with all diagram settings in the renderer +%End + void setDiagramSettings( const QgsDiagramSettings &s ); + + virtual QList diagramAttributes() const; + + + + virtual QString rendererName() const; + + virtual void readXml( const QDomElement &elem, const QgsReadWriteContext &context ); + + virtual void writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; + + + void _readXmlSubRenderers( const QDomElement &elem, const QgsReadWriteContext &context ); +%Docstring +Reads stacked renderers state from a DOM element. + +.. seealso:: _writeXmlSubRenderers +%End - virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = 0 ) const; + void _writeXmlSubRenderers( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; +%Docstring +Writes stacked renderers state to a DOM element. + +.. seealso:: _readXmlSubRenderers +%End + + virtual QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const /Factory/; + + + QList< QgsDiagramRenderer * > renderers() const; +%Docstring +Returns an ordered list with the renderers of the stacked renderer object. +If the stacked diagram orientation is vertical, the list is returned backwards. +%End + + void addRenderer( QgsDiagramRenderer *renderer ); +%Docstring +Adds a renderer to the stacked renderer object. + +:param renderer: diagram renderer to be added to the stacked renderer + Renderers added first will render their diagrams first, i.e., more to + the left (horizontal mode) or more to the top (vertical mode). +%End + + const QgsDiagramRenderer *renderer( const int index ) const; +%Docstring +Returns the renderer at the given ``index``. +@param index index of the disired renderer in the stacked renderer +%End + + int rendererCount() const; +%Docstring +Returns the number of renderers that this stacked renderer is composed of. +%End + + protected: + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const; + + virtual QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const; }; + /************************************************************************ * This file has been generated automatically from * * * diff --git a/src/core/diagram/qgsstackeddiagram.cpp b/src/core/diagram/qgsstackeddiagram.cpp index a1e0596d4865..0c74921c004c 100644 --- a/src/core/diagram/qgsstackeddiagram.cpp +++ b/src/core/diagram/qgsstackeddiagram.cpp @@ -33,70 +33,6 @@ QgsStackedDiagram *QgsStackedDiagram::clone() const return new QgsStackedDiagram( *this ); } -void QgsStackedDiagram::addSubDiagram( QgsDiagram *diagram, QgsDiagramSettings *s ) -{ - mSubDiagrams.append( DiagramData{diagram, s} ); -} - -int QgsStackedDiagram::subDiagramCount() const -{ - return mSubDiagrams.count(); -} - -QString QgsStackedDiagram::subDiagramType( int index ) const -{ - if ( index >= 0 && index < mSubDiagrams.count() ) - { - return mSubDiagrams.at( index ).diagram->diagramName(); - } - return QString(); -} - -QList< QgsDiagram * > QgsStackedDiagram::subDiagrams( const QgsDiagramSettings &s ) const -{ - QList< QgsDiagram * > diagrams; - - if ( s.stackedDiagramMode == QgsDiagramSettings::Horizontal ) - { - for ( const auto &item : std::as_const( mSubDiagrams ) ) - { - diagrams.append( item.diagram ); - } - } - else - { - // We'll draw vertical diagrams backwards, - // so we return the subdiagrams in reverse order - QList< DiagramData >::const_reverse_iterator iter = mSubDiagrams.rbegin(); - for ( ; iter != mSubDiagrams.rend(); ++iter ) - { - diagrams.append( iter->diagram ); - } - } - return diagrams; -} - -QgsDiagramSettings *QgsStackedDiagram::subDiagramSettings( int index ) const -{ - if ( index >= 0 && index < mSubDiagrams.count() ) - { - return mSubDiagrams.at( index ).settings; - } - return nullptr; -} - -QgsDiagramSettings *QgsStackedDiagram::subDiagramSettings( const QgsDiagram *diagram ) const -{ - for ( const auto &item : std::as_const( mSubDiagrams ) ) - { - if ( item.diagram == diagram ) - { - return item.settings; - } - } - return nullptr; -} - void QgsStackedDiagram::subDiagramPosition( QPointF &newPos, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramSettings &subSettings ) { QSizeF size = sizePainterUnits( subSettings.size, subSettings, c ); @@ -114,72 +50,19 @@ void QgsStackedDiagram::subDiagramPosition( QPointF &newPos, const QgsRenderCont QSizeF QgsStackedDiagram::diagramSize( const QgsFeature &feature, const QgsRenderContext &c, const QgsDiagramSettings &s, const QgsDiagramInterpolationSettings &is ) { - QSizeF size( 0, 0 ); - if ( feature.attributeCount() == 0 || mSubDiagrams.length() == 0 ) - { - return size; //zero size if no attributes or no subdiagrams - } - - // Iterate subdiagramas and sum their individual sizes - for ( const auto &item : std::as_const( mSubDiagrams ) ) - { - //size += item.diagram->diagramSize( feature, c, *item.settings, is ); - const QSizeF subSize = item.diagram->diagramSize( feature, c, *item.settings, is ); - switch ( s.stackedDiagramMode ) - { - case QgsDiagramSettings::Horizontal: - size.setWidth( size.width() + subSize.width() ); - size.setHeight( subSize.height() ); - break; - - case QgsDiagramSettings::Vertical: - size.setWidth( subSize.width() ); - size.setHeight( size.height() + subSize.height() ); - break; - } - } - - // eh - this method returns size in unknown units ...! We'll have to fake it and use a rough estimation of - // a conversion factor to painter units... - // TODO QGIS 4.0 -- these methods should all use painter units, dependent on the render context scaling... - double painterUnitConversionScale = c.convertToPainterUnits( 1, s.sizeType ); - - const double spacing = c.convertToPainterUnits( s.stackedDiagramSpacing(), s.stackedDiagramSpacingUnit(), s.stackedDiagramSpacingMapUnitScale() ) / painterUnitConversionScale; - - switch ( s.stackedDiagramMode ) - { - case QgsDiagramSettings::Horizontal: - size.scale( size.width() + spacing * ( mSubDiagrams.length() - 1 ), size.height(), Qt::IgnoreAspectRatio ); - break; - - case QgsDiagramSettings::Vertical: - size.scale( size.width(), size.height() + spacing * ( mSubDiagrams.length() - 1 ), Qt::IgnoreAspectRatio ); - break; - } - - if ( s.showAxis() && s.axisLineSymbol() ) - { - const double maxBleed = QgsSymbolLayerUtils::estimateMaxSymbolBleed( s.axisLineSymbol(), c ) / painterUnitConversionScale; - size.setWidth( size.width() + 2 * maxBleed ); - size.setHeight( size.height() + 2 * maxBleed ); - } - - return size; + Q_UNUSED( feature ) + Q_UNUSED( c ) + Q_UNUSED( s ) + Q_UNUSED( is ) + return QSize( 0, 0 ); } double QgsStackedDiagram::legendSize( double value, const QgsDiagramSettings &s, const QgsDiagramInterpolationSettings &is ) const { - if ( qgsDoubleNear( is.upperValue, is.lowerValue ) ) - return s.minimumSize; // invalid value range => zero size - - // Scale, if extension is smaller than the specified minimum - if ( value < s.minimumSize ) - { - value = s.minimumSize; - } - - double scaleFactor = ( ( is.upperSize.width() - is.lowerSize.width() ) / ( is.upperValue - is.lowerValue ) ); - return value * scaleFactor; + Q_UNUSED( value ) + Q_UNUSED( s ) + Q_UNUSED( is ) + return 0; } QString QgsStackedDiagram::diagramName() const @@ -189,58 +72,10 @@ QString QgsStackedDiagram::diagramName() const QSizeF QgsStackedDiagram::diagramSize( const QgsAttributes &attributes, const QgsRenderContext &c, const QgsDiagramSettings &s ) { - QSizeF size( 0, 0 ); - if ( attributes.isEmpty() || mSubDiagrams.length() == 0 ) - { - return size; //zero size if no attributes or no subdiagrams - } - - // Iterate subdiagramas and sum their individual sizes - // accounting for stacked diagram defined spacing - for ( const auto &item : std::as_const( mSubDiagrams ) ) - { - //size += item.diagram->diagramSize( attributes, c, *item.settings ); - const QSizeF subSize = item.diagram->diagramSize( attributes, c, *item.settings ); - switch ( s.stackedDiagramMode ) - { - case QgsDiagramSettings::Horizontal: - size.setWidth( size.width() + subSize.width() ); - size.setHeight( subSize.height() ); - break; - - case QgsDiagramSettings::Vertical: - size.setWidth( subSize.width() ); - size.setHeight( size.height() + subSize.height() ); - break; - } - } - - // eh - this method returns size in unknown units ...! We'll have to fake it and use a rough estimation of - // a conversion factor to painter units... - // TODO QGIS 4.0 -- these methods should all use painter units, dependent on the render context scaling... - double painterUnitConversionScale = c.convertToPainterUnits( 1, s.sizeType ); - - const double spacing = c.convertToPainterUnits( s.stackedDiagramSpacing(), s.stackedDiagramSpacingUnit(), s.stackedDiagramSpacingMapUnitScale() ) / painterUnitConversionScale; - - switch ( s.stackedDiagramMode ) - { - case QgsDiagramSettings::Horizontal: - size.scale( size.width() + spacing * ( mSubDiagrams.length() - 1 ), size.height(), Qt::IgnoreAspectRatio ); - break; - - case QgsDiagramSettings::Vertical: - size.scale( size.width(), size.height() + spacing * ( mSubDiagrams.length() - 1 ), Qt::IgnoreAspectRatio ); - break; - } - - if ( s.showAxis() && s.axisLineSymbol() ) - { - const double maxBleed = QgsSymbolLayerUtils::estimateMaxSymbolBleed( s.axisLineSymbol(), c ) / painterUnitConversionScale; - size.setWidth( size.width() + 2 * maxBleed ); - size.setHeight( size.height() + 2 * maxBleed ); - } - - return size; + Q_UNUSED( attributes ) + Q_UNUSED( c ) + Q_UNUSED( s ) + return QSizeF( 0, 0 ); } void QgsStackedDiagram::renderDiagram( const QgsFeature &feature, QgsRenderContext &c, const QgsDiagramSettings &s, QPointF position ) diff --git a/src/core/diagram/qgsstackeddiagram.h b/src/core/diagram/qgsstackeddiagram.h index a8fe74be4973..97f3e3cc1963 100644 --- a/src/core/diagram/qgsstackeddiagram.h +++ b/src/core/diagram/qgsstackeddiagram.h @@ -41,48 +41,10 @@ class CORE_EXPORT QgsStackedDiagram : public QgsDiagram SIP_NODEFAULTCTORS { public: - struct DiagramData - { - QgsDiagram *diagram = nullptr; - QgsDiagramSettings *settings = nullptr; - }; - QgsStackedDiagram(); QgsStackedDiagram *clone() const override SIP_FACTORY; - /** - * Adds a subdiagram to the stacked diagram object along with its corresponding settings. - * \param diagram subdiagram to be added to the stacked diagram - * \param s subdiagram settings - * Subdiagrams added first will appear more to the left (if stacked diagram is horizontal), - * or more to the top (if stacked diagram is vertical). - */ - void addSubDiagram( QgsDiagram *diagram, QgsDiagramSettings *s ); - - /** - * Returns the number of subdiagrams that this stacked diagram is composed of. - */ - int subDiagramCount() const; - - /** - * Returns the type of the subdiagram located at a given \a index. - */ - QString subDiagramType( int index ) const; - - /** - * Returns an ordered list with the subdiagrams of the stacked diagram object. - * If the stacked diagram orientation is vertical, the list is returned backwards. - * \param s stacked diagram settings - */ - QList< QgsDiagram * > subDiagrams( const QgsDiagramSettings &s ) const; - - //! Returns the settings associated to the \a diagram. - QgsDiagramSettings *subDiagramSettings( const QgsDiagram *diagram ) const; - - //! Returns the diagram settings for the diagram located at a given \a index. - QgsDiagramSettings *subDiagramSettings( int index ) const; - /** * Calculates the position for the next subdiagram, updating the \a newPos object. * \param newPos out: position of the previous diagram @@ -103,7 +65,6 @@ class CORE_EXPORT QgsStackedDiagram : public QgsDiagram SIP_NODEFAULTCTORS QBrush mCategoryBrush; QPen mPen; double mScaleFactor; - QList< DiagramData > mSubDiagrams; }; #endif // QGSSTACKEDDIAGRAM_H diff --git a/src/core/qgsdiagramrenderer.cpp b/src/core/qgsdiagramrenderer.cpp index deca426696f5..fa9a8cbe1c92 100644 --- a/src/core/qgsdiagramrenderer.cpp +++ b/src/core/qgsdiagramrenderer.cpp @@ -503,67 +503,26 @@ void QgsDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderCont return; } - if ( mDiagram->diagramName() == QStringLiteral( "Stacked" ) ) + if ( properties.hasActiveProperties() ) { - // Iterate subdiagrams and render them individually - QgsStackedDiagram *stackedDiagram = qgis::down_cast< QgsStackedDiagram *>( mDiagram.get() ); - QList< QgsDiagram * > subDiagrams = stackedDiagram->subDiagrams( s ); - QPointF newPos = pos; // Each subdiagram will have its own newPos - - for ( const auto &subDiagram : std::as_const( subDiagrams ) ) - { - QgsDiagramSettings subSettings; - if ( !diagramSettings( feature, c, subSettings, subDiagram ) ) - { - continue; - } - - if ( properties.hasActiveProperties() ) - { - c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( subSettings.backgroundColor ) ); - subSettings.backgroundColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::BackgroundColor, c.expressionContext(), subSettings.backgroundColor ); - c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( subSettings.penColor ) ); - subSettings.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), subSettings.penColor ); - c.expressionContext().setOriginalValueVariable( subSettings.penWidth ); - subSettings.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), subSettings.penWidth ); - c.expressionContext().setOriginalValueVariable( subSettings.rotationOffset ); - subSettings.rotationOffset = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StartAngle, c.expressionContext(), subSettings.rotationOffset ); - } - - QgsPaintEffect *effect = subSettings.paintEffect(); - std::unique_ptr< QgsEffectPainter > effectPainter; - if ( effect && effect->enabled() ) - { - effectPainter = std::make_unique< QgsEffectPainter >( c, effect ); - } - - subDiagram->renderDiagram( feature, c, subSettings, newPos ); - stackedDiagram->subDiagramPosition( newPos, c, s, subSettings ); - } + c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.backgroundColor ) ); + s.backgroundColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::BackgroundColor, c.expressionContext(), s.backgroundColor ); + c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.penColor ) ); + s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), s.penColor ); + c.expressionContext().setOriginalValueVariable( s.penWidth ); + s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), s.penWidth ); + c.expressionContext().setOriginalValueVariable( s.rotationOffset ); + s.rotationOffset = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StartAngle, c.expressionContext(), s.rotationOffset ); } - else - { - if ( properties.hasActiveProperties() ) - { - c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.backgroundColor ) ); - s.backgroundColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::BackgroundColor, c.expressionContext(), s.backgroundColor ); - c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.penColor ) ); - s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), s.penColor ); - c.expressionContext().setOriginalValueVariable( s.penWidth ); - s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), s.penWidth ); - c.expressionContext().setOriginalValueVariable( s.rotationOffset ); - s.rotationOffset = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StartAngle, c.expressionContext(), s.rotationOffset ); - } - QgsPaintEffect *effect = s.paintEffect(); - std::unique_ptr< QgsEffectPainter > effectPainter; - if ( effect && effect->enabled() ) - { - effectPainter = std::make_unique< QgsEffectPainter >( c, effect ); - } - - mDiagram->renderDiagram( feature, c, s, pos ); + QgsPaintEffect *effect = s.paintEffect(); + std::unique_ptr< QgsEffectPainter > effectPainter; + if ( effect && effect->enabled() ) + { + effectPainter = std::make_unique< QgsEffectPainter >( c, effect ); } + + mDiagram->renderDiagram( feature, c, s, pos ); } QSizeF QgsDiagramRenderer::sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const @@ -652,7 +611,7 @@ void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteCo } else if ( diagramType == QLatin1String( "Stacked" ) ) { - _readXmlSubdiagrams( elem, context ); + mDiagram.reset( new QgsStackedDiagram() ); } else { @@ -662,67 +621,6 @@ void QgsDiagramRenderer::_readXml( const QDomElement &elem, const QgsReadWriteCo mShowAttributeLegend = ( elem.attribute( QStringLiteral( "attributeLegend" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) ); } -void QgsDiagramRenderer::_readXmlSubdiagrams( const QDomElement &elem, const QgsReadWriteContext &context ) -{ - Q_UNUSED( context ) - const QDomElement subdiagramsElem = elem.firstChildElement( QStringLiteral( "Subdiagrams" ) ); - - if ( !subdiagramsElem.isNull() ) - { - const QDomNodeList subdiagrams = elem.elementsByTagName( QStringLiteral( "Subdiagram" ) ); - - if ( subdiagrams.length() > 0 ) - { - std::unique_ptr< QgsStackedDiagram > stackedDiagram = std::make_unique< QgsStackedDiagram >(); - - for ( int i = 0; i < subdiagrams.size(); i++ ) - { - const QDomElement subdiagramElem = subdiagrams.at( i ).toElement(); - const QString diagramType = subdiagramElem.attribute( QStringLiteral( "diagramType" ) ); - const QDomElement categoryElem = subdiagramElem.firstChildElement( QStringLiteral( "DiagramCategory" ) ); - - if ( !categoryElem.isNull() ) - { - std::unique_ptr< QgsDiagram > diagram; - std::unique_ptr< QgsDiagramSettings > ds = std::make_unique< QgsDiagramSettings >(); - ds->readXml( categoryElem, context ); - - if ( diagramType == QLatin1String( "Pie" ) ) - { - diagram = std::make_unique< QgsPieDiagram >(); - } - else if ( diagramType == QLatin1String( "Text" ) ) - { - diagram = std::make_unique< QgsTextDiagram >(); - } - else if ( diagramType == QLatin1String( "Histogram" ) ) - { - diagram = std::make_unique< QgsHistogramDiagram >(); - } - else if ( diagramType == QLatin1String( "StackedBar" ) ) - { - diagram = std::make_unique< QgsStackedBarDiagram >(); - } - - if ( diagram ) - { - stackedDiagram->addSubDiagram( diagram.release(), ds.release() ); - } - } - } - - if ( stackedDiagram->subDiagramCount() > 1 ) - { - mDiagram.reset( stackedDiagram.release() ); - return; - } - } - } - - // Fallback - mDiagram.reset( new QgsStackedDiagram() ); -} - void QgsDiagramRenderer::_writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const { Q_UNUSED( doc ) @@ -735,60 +633,21 @@ void QgsDiagramRenderer::_writeXml( QDomElement &rendererElem, QDomDocument &doc rendererElem.setAttribute( QStringLiteral( "attributeLegend" ), mShowAttributeLegend ); } -void QgsDiagramRenderer::_writeXmlSubDiagrams( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const -{ - QDomElement subDiagramsElem = doc.createElement( QStringLiteral( "Subdiagrams" ) ); - - // Iterate subdiagrams and write their settings to a DOM object - const QgsStackedDiagram *stackedDiagram = qgis::down_cast< const QgsStackedDiagram *>( mDiagram.get() ); - - for ( int i = 0; i < stackedDiagram->subDiagramCount(); i++ ) - { - QDomElement subDiagramElem = doc.createElement( QStringLiteral( "Subdiagram" ) ); - subDiagramElem.setAttribute( QStringLiteral( "diagramType" ), stackedDiagram->subDiagramType( i ) ); - const QgsDiagramSettings *subSettings = stackedDiagram->subDiagramSettings( i ); - subSettings->writeXml( subDiagramElem, doc, context ); - subDiagramsElem.appendChild( subDiagramElem ); - } - rendererElem.appendChild( subDiagramsElem ); -} - QgsSingleCategoryDiagramRenderer *QgsSingleCategoryDiagramRenderer::clone() const { return new QgsSingleCategoryDiagramRenderer( *this ); } -bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsFeature &, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram ) const +bool QgsSingleCategoryDiagramRenderer::diagramSettings( const QgsFeature &, const QgsRenderContext &c, QgsDiagramSettings &s ) const { Q_UNUSED( c ) - if ( subDiagram ) - { - // Stacked diagram case, ask the stacked - // diagram object for its subdiagram settings - QgsStackedDiagram *stackedDiagram = qgis::down_cast< QgsStackedDiagram * >( mDiagram.get() ); - s = *stackedDiagram->subDiagramSettings( subDiagram ); - } - else - { - s = mSettings; - } + s = mSettings; return true; } -QSizeF QgsSingleCategoryDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagram *subDiagram ) const +QSizeF QgsSingleCategoryDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const { - if ( subDiagram ) - { - // Stacked diagram case, ask the stacked - // diagram object for its diagram settings - QgsStackedDiagram *stackedDiagram = qgis::down_cast< QgsStackedDiagram * >( mDiagram.get() ); - QgsDiagramSettings subDiagramSettings = *stackedDiagram->subDiagramSettings( subDiagram ); - return subDiagram->diagramSize( feature.attributes(), c, subDiagramSettings ); - } - else - { - return mDiagram->diagramSize( feature.attributes(), c, mSettings ); - } + return mDiagram->diagramSize( feature.attributes(), c, mSettings ); } QList QgsSingleCategoryDiagramRenderer::diagramSettings() const @@ -815,12 +674,6 @@ void QgsSingleCategoryDiagramRenderer::writeXml( QDomElement &layerElem, QDomDoc QDomElement rendererElem = doc.createElement( QStringLiteral( "SingleCategoryDiagramRenderer" ) ); mSettings.writeXml( rendererElem, doc, context ); _writeXml( rendererElem, doc, context ); - - if ( mDiagram->diagramName() == QStringLiteral( "Stacked" ) ) - { - _writeXmlSubDiagrams( rendererElem, doc, context ); - } - layerElem.appendChild( rendererElem ); } @@ -867,19 +720,10 @@ QList QgsLinearlyInterpolatedDiagramRenderer::diagramSetting return settingsList; } -bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram ) const +bool QgsLinearlyInterpolatedDiagramRenderer::diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const { - if ( subDiagram ) - { - QgsStackedDiagram *stackedDiagram = qgis::down_cast< QgsStackedDiagram * >( mDiagram.get() ); - s = *stackedDiagram->subDiagramSettings( subDiagram ); - s.size = diagramSize( feature, c, subDiagram ); - } - else - { - s = mSettings; - s.size = diagramSize( feature, c ); - } + s = mSettings; + s.size = diagramSize( feature, c ); return true; } @@ -907,20 +751,9 @@ QSet QgsLinearlyInterpolatedDiagramRenderer::referencedFields( const Qg return referenced; } -QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagram *subDiagram ) const +QSizeF QgsLinearlyInterpolatedDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const { - if ( subDiagram ) - { - // Stacked diagram case, ask the stacked - // diagram object for its diagram settings - QgsStackedDiagram *stackedDiagram = qgis::down_cast< QgsStackedDiagram * >( mDiagram.get() ); - QgsDiagramSettings subDiagramSettings = *stackedDiagram->subDiagramSettings( subDiagram ); - return subDiagram->diagramSize( feature, c, subDiagramSettings, mInterpolationSettings ); - } - else - { - return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings ); - } + return mDiagram->diagramSize( feature, c, mSettings, mInterpolationSettings ); } void QgsLinearlyInterpolatedDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) @@ -1001,15 +834,258 @@ void QgsLinearlyInterpolatedDiagramRenderer::writeXml( QDomElement &layerElem, Q } _writeXml( rendererElem, doc, context ); + layerElem.appendChild( rendererElem ); +} + +QgsStackedDiagramRenderer *QgsStackedDiagramRenderer::clone() const +{ + return new QgsStackedDiagramRenderer( *this ); +} + +QSizeF QgsStackedDiagramRenderer::sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const +{ + QSizeF stackedSize( 0, 0 ); + + // Iterate renderers. For each renderer, get the diagram + // size for the feature and add it to the total size + // accounting for stacked diagram defined spacing + for ( int i = 0; i < mDiagramRenderers.count(); i++ ) + { + QSizeF size = mDiagramRenderers.at( i )->sizeMapUnits( feature, c ); + + if ( size.isValid() ) + { + switch ( mSettings.stackedDiagramMode ) + { + case QgsDiagramSettings::Horizontal: + stackedSize.setWidth( stackedSize.width() + size.width() ); + stackedSize.setHeight( std::max( stackedSize.height(), size.height() ) ); + break; + + case QgsDiagramSettings::Vertical: + stackedSize.setWidth( std::max( stackedSize.width(), size.width() ) ); + stackedSize.setHeight( stackedSize.height() + size.height() ); + break; + } + } + } + + const double spacing = c.convertToMapUnits( mSettings.stackedDiagramSpacing(), mSettings.stackedDiagramSpacingUnit(), mSettings.stackedDiagramSpacingMapUnitScale() ); + + switch ( mSettings.stackedDiagramMode ) + { + case QgsDiagramSettings::Horizontal: + stackedSize.scale( stackedSize.width() + spacing * ( mDiagramRenderers.count() - 1 ), stackedSize.height(), Qt::IgnoreAspectRatio ); + break; + + case QgsDiagramSettings::Vertical: + stackedSize.scale( stackedSize.width(), stackedSize.height() + spacing * ( mDiagramRenderers.count() - 1 ), Qt::IgnoreAspectRatio ); + break; + } + return stackedSize; +} + +void QgsStackedDiagramRenderer::renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties ) const +{ + if ( !mDiagram ) + { + return; + } + + QPointF newPos = pos; // Each subdiagram will have its own newPos + QList< QgsDiagramRenderer * > stackedRenderers = renderers(); + for ( const auto &stackedRenderer : std::as_const( stackedRenderers ) ) + { + if ( stackedRenderer->rendererName() == QStringLiteral( "Stacked" ) ) + { + stackedRenderer->renderDiagram( feature, c, newPos, properties ); + continue; + } + + QgsDiagramSettings s; + if ( !stackedRenderer->diagramSettings( feature, c, s ) ) + { + return; + } - if ( mDiagram->diagramName() == QStringLiteral( "Stacked" ) ) + if ( properties.hasActiveProperties() ) + { + c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.backgroundColor ) ); + s.backgroundColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::BackgroundColor, c.expressionContext(), s.backgroundColor ); + c.expressionContext().setOriginalValueVariable( QgsColorUtils::colorToString( s.penColor ) ); + s.penColor = properties.valueAsColor( QgsDiagramLayerSettings::Property::StrokeColor, c.expressionContext(), s.penColor ); + c.expressionContext().setOriginalValueVariable( s.penWidth ); + s.penWidth = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StrokeWidth, c.expressionContext(), s.penWidth ); + c.expressionContext().setOriginalValueVariable( s.rotationOffset ); + s.rotationOffset = properties.valueAsDouble( QgsDiagramLayerSettings::Property::StartAngle, c.expressionContext(), s.rotationOffset ); + } + + QgsPaintEffect *effect = s.paintEffect(); + std::unique_ptr< QgsEffectPainter > effectPainter; + if ( effect && effect->enabled() ) + { + effectPainter = std::make_unique< QgsEffectPainter >( c, effect ); + } + + stackedRenderer->diagram()->renderDiagram( feature, c, s, newPos ); + QgsStackedDiagram *stackedDiagram = dynamic_cast< QgsStackedDiagram *>( mDiagram.get() ); + stackedDiagram->subDiagramPosition( newPos, c, mSettings, s ); + } +} + +bool QgsStackedDiagramRenderer::diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const +{ + Q_UNUSED( feature ) + Q_UNUSED( c ) + Q_UNUSED( s ) + return false; +} + +QSizeF QgsStackedDiagramRenderer::diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const +{ + Q_UNUSED( feature ) + Q_UNUSED( c ) + return QSizeF( 0, 0 ); +} + +QList QgsStackedDiagramRenderer::diagramSettings() const +{ + QList settingsList; + settingsList.push_back( mSettings ); + return settingsList; +} + +QList QgsStackedDiagramRenderer::diagramAttributes() const +{ + return mSettings.categoryAttributes; +} + +QList< QgsLayerTreeModelLegendNode * > QgsStackedDiagramRenderer::legendItems( QgsLayerTreeLayer *nodeLayer ) const +{ + QList< QgsLayerTreeModelLegendNode * > nodes; + for ( int i = 0; i < rendererCount(); i++ ) { - _writeXmlSubDiagrams( rendererElem, doc, context ); + nodes << mDiagramRenderers.at( i )->legendItems( nodeLayer ); } + return nodes; +} + +QList< QgsDiagramRenderer * > QgsStackedDiagramRenderer::renderers() const +{ + QList< QgsDiagramRenderer * > renderers; + + if ( mSettings.stackedDiagramMode == QgsDiagramSettings::Horizontal ) + { + for ( const auto &item : std::as_const( mDiagramRenderers ) ) + { + renderers.append( item ); + } + } + else + { + // We draw vertical diagrams backwards, so + // we return the subdiagrams in reverse order + QList< QgsDiagramRenderer * >::const_reverse_iterator iter = mDiagramRenderers.rbegin(); + for ( ; iter != mDiagramRenderers.rend(); ++iter ) + { + renderers.append( *iter ); + } + } + return renderers; +} + +void QgsStackedDiagramRenderer::addRenderer( QgsDiagramRenderer *renderer ) +{ + if ( renderer ) + { + mDiagramRenderers.append( renderer ); + } +} + +const QgsDiagramRenderer *QgsStackedDiagramRenderer::renderer( const int index ) const +{ + if ( index >= 0 && index < mDiagramRenderers.count() ) + { + return mDiagramRenderers.at( index ); + } + + return nullptr; +} + +int QgsStackedDiagramRenderer::rendererCount() const +{ + return mDiagramRenderers.count(); +} + +void QgsStackedDiagramRenderer::readXml( const QDomElement &elem, const QgsReadWriteContext &context ) +{ + const QDomElement categoryElem = elem.firstChildElement( QStringLiteral( "DiagramCategory" ) ); + if ( categoryElem.isNull() ) + { + return; + } + + mSettings.readXml( categoryElem, context ); + _readXml( elem, context ); + _readXmlSubRenderers( elem, context ); +} + +void QgsStackedDiagramRenderer::_readXmlSubRenderers( const QDomElement &elem, const QgsReadWriteContext &context ) +{ + const QDomElement subRenderersElem = elem.firstChildElement( QStringLiteral( "DiagramRenderers" ) ); + + if ( !subRenderersElem.isNull() ) + { + const QDomNodeList childRendererList = subRenderersElem.childNodes(); + + for ( int i = 0; i < childRendererList.size(); i++ ) + { + const QDomElement subRendererElem = childRendererList.at( i ).toElement(); + + if ( subRendererElem.nodeName() == QStringLiteral( "SingleCategoryDiagramRenderer" ) ) + { + std::unique_ptr< QgsSingleCategoryDiagramRenderer > singleCatDiagramRenderer = std::make_unique< QgsSingleCategoryDiagramRenderer >(); + singleCatDiagramRenderer->readXml( subRendererElem, context ); + addRenderer( singleCatDiagramRenderer.release() ); + } + else if ( subRendererElem.nodeName() == QStringLiteral( "LinearlyInterpolatedDiagramRenderer" ) ) + { + std::unique_ptr< QgsLinearlyInterpolatedDiagramRenderer > linearDiagramRenderer = std::make_unique< QgsLinearlyInterpolatedDiagramRenderer >(); + linearDiagramRenderer->readXml( subRendererElem, context ); + addRenderer( linearDiagramRenderer.release() ); + } + else if ( subRendererElem.nodeName() == QStringLiteral( "StackedDiagramRenderer" ) ) + { + std::unique_ptr< QgsStackedDiagramRenderer > stackedDiagramRenderer = std::make_unique< QgsStackedDiagramRenderer >(); + stackedDiagramRenderer->readXml( subRendererElem, context ); + addRenderer( stackedDiagramRenderer.release() ); + } + } + } +} + +void QgsStackedDiagramRenderer::writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const +{ + QDomElement rendererElem = doc.createElement( QStringLiteral( "StackedDiagramRenderer" ) ); + mSettings.writeXml( rendererElem, doc, context ); + _writeXml( rendererElem, doc, context ); + _writeXmlSubRenderers( rendererElem, doc, context ); layerElem.appendChild( rendererElem ); } +void QgsStackedDiagramRenderer::_writeXmlSubRenderers( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const +{ + QDomElement renderersElem = doc.createElement( QStringLiteral( "DiagramRenderers" ) ); + + // Iterate sub renderers and write their settings to a DOM object + for ( int i = 0; i < mDiagramRenderers.count(); i++ ) + { + mDiagramRenderers.at( i )->writeXml( renderersElem, doc, context ); + } + rendererElem.appendChild( renderersElem ); +} + QList< QgsLayerTreeModelLegendNode * > QgsDiagramSettings::legendItems( QgsLayerTreeLayer *nodeLayer ) const { QList< QgsLayerTreeModelLegendNode * > list; diff --git a/src/core/qgsdiagramrenderer.h b/src/core/qgsdiagramrenderer.h index 9741602be1bb..514e43a5dc94 100644 --- a/src/core/qgsdiagramrenderer.h +++ b/src/core/qgsdiagramrenderer.h @@ -44,6 +44,7 @@ class QgsLayerTreeLayer; class QgsPaintEffect; class QgsDataDefinedSizeLegend; class QgsLineSymbol; +class QgsStackedDiagram; namespace pal { class Layer; } SIP_SKIP @@ -744,6 +745,8 @@ class CORE_EXPORT QgsDiagramRenderer sipType = sipType_QgsSingleCategoryDiagramRenderer; else if ( sipCpp->rendererName() == QLatin1String( "LinearlyInterpolated" ) ) sipType = sipType_QgsLinearlyInterpolatedDiagramRenderer; + else if ( sipCpp->rendererName() == QLatin1String( "Stacked" ) ) + sipType = sipType_QgsStackedDiagramRenderer; else sipType = NULL; SIP_END @@ -776,7 +779,7 @@ class CORE_EXPORT QgsDiagramRenderer /** * Renders the diagram for a specified feature at a specific position in the passed render context. */ - void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const; void setDiagram( QgsDiagram *d SIP_TRANSFER ); QgsDiagram *diagram() const { return mDiagram.get(); } @@ -826,17 +829,15 @@ class CORE_EXPORT QgsDiagramRenderer * \param feature the feature * \param c render context * \param s out: diagram settings for the feature - * \param subDiagram subDiagram object for stacked diagram case */ - virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = nullptr ) const = 0; + virtual bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const = 0; /** * Returns size of the diagram (in painter units) or an invalid size in case of error * \param feature the feature * \param c render context - * \param subDiagram subDiagram object for stacked diagram case */ - virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagram *subDiagram = nullptr ) const = 0; + virtual QSizeF diagramSize( const QgsFeature &feature, const QgsRenderContext &c ) const = 0; //! Converts size from mm to map units void convertSizeToMapUnits( QSizeF &size, const QgsRenderContext &context ) const; @@ -853,28 +854,18 @@ class CORE_EXPORT QgsDiagramRenderer void _readXml( const QDomElement &elem, const QgsReadWriteContext &context ); /** - * Reads Stacked Diagram's subdiagram state from a DOM element. - * \see _writeXmlSubDiagrams() - */ - void _readXmlSubdiagrams( const QDomElement &elem, const QgsReadWriteContext &context ); - - /** - * Writes internal QgsDiagramRenderer diagram state to a DOM element. - * \see _readXml() - */ + * Writes internal QgsDiagramRenderer diagram state to a DOM element. + * \see _readXml() + */ void _writeXml( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; - /** - * Writes Stacked Diagram's subdiagram state to a DOM element. - * \see _readXmlSubdiagrams() - */ - void _writeXmlSubDiagrams( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; - //! Reference to the object that does the real diagram rendering std::unique_ptr< QgsDiagram > mDiagram; //! Whether to show an attribute legend for the diagrams bool mShowAttributeLegend = true; + + friend class QgsStackedDiagramRenderer; }; /** @@ -903,9 +894,9 @@ class CORE_EXPORT QgsSingleCategoryDiagramRenderer : public QgsDiagramRenderer QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const override SIP_FACTORY; protected: - bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = nullptr ) const override; + bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const override; - QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = nullptr ) const override; + QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const override; private: QgsDiagramSettings mSettings; @@ -984,9 +975,9 @@ class CORE_EXPORT QgsLinearlyInterpolatedDiagramRenderer : public QgsDiagramRend QgsDataDefinedSizeLegend *dataDefinedSizeLegend() const; protected: - bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s, QgsDiagram *subDiagram = nullptr ) const override; + bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const override; - QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c, QgsDiagram *subDiagram = nullptr ) const override; + QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const override; private: QgsDiagramSettings mSettings; @@ -996,4 +987,92 @@ class CORE_EXPORT QgsLinearlyInterpolatedDiagramRenderer : public QgsDiagramRend QgsDataDefinedSizeLegend *mDataDefinedSizeLegend = nullptr; }; +/** + * \ingroup core + * \class QgsStackedDiagramRenderer + * Renders diagrams using mixed diagram render types. The size of + * the rendered diagram is given by a combination of subrenderers. + * + * \since QGIS 3.40 + */ +class CORE_EXPORT QgsStackedDiagramRenderer : public QgsDiagramRenderer +{ + public: + QgsStackedDiagramRenderer() = default; + + QgsStackedDiagramRenderer *clone() const override SIP_FACTORY; + + //! Returns size of the diagram for a feature in map units. Returns an invalid QSizeF in case of error + virtual QSizeF sizeMapUnits( const QgsFeature &feature, const QgsRenderContext &c ) const override; + + /** + * Renders the diagram for a specified feature at a specific position in the + * passed render context, taking all renderers and their own diagrams into account. + * Diagram rendering is delegated to renderer's diagram. + */ + virtual void renderDiagram( const QgsFeature &feature, QgsRenderContext &c, QPointF pos, const QgsPropertyCollection &properties = QgsPropertyCollection() ) const override; + + //! Returns list with all diagram settings in the renderer + QList diagramSettings() const override; + + void setDiagramSettings( const QgsDiagramSettings &s ) { mSettings = s; } + + QList diagramAttributes() const override; + + //QSet< QString > referencedFields( const QgsExpressionContext &context = QgsExpressionContext() ) const override; + + QString rendererName() const override { return QStringLiteral( "Stacked" ); } + + void readXml( const QDomElement &elem, const QgsReadWriteContext &context ) override; + void writeXml( QDomElement &layerElem, QDomDocument &doc, const QgsReadWriteContext &context ) const override; + + /** + * Reads stacked renderers state from a DOM element. + * \see _writeXmlSubRenderers() + */ + void _readXmlSubRenderers( const QDomElement &elem, const QgsReadWriteContext &context ); + + /** + * Writes stacked renderers state to a DOM element. + * \see _readXmlSubRenderers() + */ + void _writeXmlSubRenderers( QDomElement &rendererElem, QDomDocument &doc, const QgsReadWriteContext &context ) const; + + QList< QgsLayerTreeModelLegendNode * > legendItems( QgsLayerTreeLayer *nodeLayer ) const override SIP_FACTORY; + + /** + * Returns an ordered list with the renderers of the stacked renderer object. + * If the stacked diagram orientation is vertical, the list is returned backwards. + */ + QList< QgsDiagramRenderer * > renderers() const; + + /** + * Adds a renderer to the stacked renderer object. + * \param renderer diagram renderer to be added to the stacked renderer + * Renderers added first will render their diagrams first, i.e., more to + * the left (horizontal mode) or more to the top (vertical mode). + */ + void addRenderer( QgsDiagramRenderer *renderer ); + + /** + * Returns the renderer at the given \a index. + * @param index index of the disired renderer in the stacked renderer + */ + const QgsDiagramRenderer *renderer( const int index ) const; + + /** + * Returns the number of renderers that this stacked renderer is composed of. + */ + int rendererCount() const; + + protected: + bool diagramSettings( const QgsFeature &feature, const QgsRenderContext &c, QgsDiagramSettings &s ) const override; + QSizeF diagramSize( const QgsFeature &, const QgsRenderContext &c ) const override; + + private: + QgsDiagramSettings mSettings; + QList< QgsDiagramRenderer * > mDiagramRenderers; +}; + + #endif // QGSDIAGRAMRENDERER_H diff --git a/src/core/vector/qgsvectorlayer.cpp b/src/core/vector/qgsvectorlayer.cpp index e37ffe6a8483..7810f5273e64 100644 --- a/src/core/vector/qgsvectorlayer.cpp +++ b/src/core/vector/qgsvectorlayer.cpp @@ -2926,6 +2926,12 @@ bool QgsVectorLayer::readStyle( const QDomNode &node, QString &errorMessage, mDiagramRenderer = new QgsLinearlyInterpolatedDiagramRenderer(); mDiagramRenderer->readXml( linearDiagramElem, context ); } + QDomElement stackedDiagramElem = node.firstChildElement( QStringLiteral( "StackedDiagramRenderer" ) ); + if ( !stackedDiagramElem.isNull() ) + { + mDiagramRenderer = new QgsStackedDiagramRenderer(); + mDiagramRenderer->readXml( stackedDiagramElem, context ); + } if ( mDiagramRenderer ) { diff --git a/src/gui/vector/qgsdiagramproperties.cpp b/src/gui/vector/qgsdiagramproperties.cpp index d7f3753940ea..db6613369bd7 100644 --- a/src/gui/vector/qgsdiagramproperties.cpp +++ b/src/gui/vector/qgsdiagramproperties.cpp @@ -270,10 +270,14 @@ QgsDiagramProperties::QgsDiagramProperties( QgsVectorLayer *layer, QWidget *pare connect( mButtonSizeLegendSettings, &QPushButton::clicked, this, &QgsDiagramProperties::showSizeLegendDialog ); } -void QgsDiagramProperties::syncToLayer() +void QgsDiagramProperties::syncToLayer( const QgsDiagramRenderer *dr ) { mDiagramAttributesTreeWidget->clear(); - const QgsDiagramRenderer *dr = mLayer->diagramRenderer(); + if ( !dr ) + { + dr = mLayer->diagramRenderer(); + } + if ( !dr ) //no diagram renderer yet, insert reasonable default { mFixedSizeRadio->setChecked( true ); @@ -323,8 +327,6 @@ void QgsDiagramProperties::syncToLayer() } else // already a diagram renderer present { - const QgsStackedDiagram *stackedDiagram = nullptr; - //single category renderer or interpolated one? if ( dr->rendererName() == QLatin1String( "SingleCategory" ) ) { @@ -338,48 +340,28 @@ void QgsDiagramProperties::syncToLayer() mLinearScaleFrame->setEnabled( mAttributeBasedScalingRadio->isChecked() ); mCheckBoxAttributeLegend->setChecked( dr->attributeLegend() ); - bool diagramSettingsSet = false; - QgsDiagramSettings diagramSettings; + // Assume single category or linearly interpolated diagram renderer for now. + const QList settingList = dr->diagramSettings(); - if ( dr->diagram() && mSubDiagramIndex >= 0 ) + if ( !settingList.isEmpty() ) { - // The current diagram is a subdiagram of a stacked diagram. - // Get the diagram settings using the subdiagram index. - stackedDiagram = dynamic_cast< QgsStackedDiagram * >( dr->diagram() ); - diagramSettings = *stackedDiagram->subDiagramSettings( mSubDiagramIndex ); - diagramSettingsSet = true; - } - else // Single diagram case - { - // Assume single category or linearly interpolated diagram renderer for now. - const QList settingList = dr->diagramSettings(); - - if ( !settingList.isEmpty() ) - { - diagramSettings = settingList.at( 0 ); - diagramSettingsSet = true; - } - } - - if ( diagramSettingsSet ) - { - mDiagramFrame->setEnabled( diagramSettings.enabled ); - mDiagramFontButton->setCurrentFont( diagramSettings.font ); - const QSizeF size = diagramSettings.size; - mBackgroundColorButton->setColor( diagramSettings.backgroundColor ); - mOpacityWidget->setOpacity( diagramSettings.opacity ); - mDiagramPenColorButton->setColor( diagramSettings.penColor ); - mPenWidthSpinBox->setValue( diagramSettings.penWidth ); + mDiagramFrame->setEnabled( settingList.at( 0 ).enabled ); + mDiagramFontButton->setCurrentFont( settingList.at( 0 ).font ); + const QSizeF size = settingList.at( 0 ).size; + mBackgroundColorButton->setColor( settingList.at( 0 ).backgroundColor ); + mOpacityWidget->setOpacity( settingList.at( 0 ).opacity ); + mDiagramPenColorButton->setColor( settingList.at( 0 ).penColor ); + mPenWidthSpinBox->setValue( settingList.at( 0 ).penWidth ); mDiagramSizeSpinBox->setValue( ( size.width() + size.height() ) / 2.0 ); - mScaleRangeWidget->setScaleRange( ( diagramSettings.minimumScale > 0 ? diagramSettings.minimumScale : mLayer->minimumScale() ), - ( diagramSettings.maximumScale > 0 ? diagramSettings.maximumScale : mLayer->maximumScale() ) ); - mScaleVisibilityGroupBox->setChecked( diagramSettings.scaleBasedVisibility ); - mDiagramUnitComboBox->setUnit( diagramSettings.sizeType ); - mDiagramUnitComboBox->setMapUnitScale( diagramSettings.sizeScale ); - mDiagramLineUnitComboBox->setUnit( diagramSettings.lineSizeUnit ); - mDiagramLineUnitComboBox->setMapUnitScale( diagramSettings.lineSizeScale ); - - if ( diagramSettings.labelPlacementMethod == QgsDiagramSettings::Height ) + mScaleRangeWidget->setScaleRange( ( settingList.at( 0 ).minimumScale > 0 ? settingList.at( 0 ).minimumScale : mLayer->minimumScale() ), + ( settingList.at( 0 ).maximumScale > 0 ? settingList.at( 0 ).maximumScale : mLayer->maximumScale() ) ); + mScaleVisibilityGroupBox->setChecked( settingList.at( 0 ).scaleBasedVisibility ); + mDiagramUnitComboBox->setUnit( settingList.at( 0 ).sizeType ); + mDiagramUnitComboBox->setMapUnitScale( settingList.at( 0 ).sizeScale ); + mDiagramLineUnitComboBox->setUnit( settingList.at( 0 ).lineSizeUnit ); + mDiagramLineUnitComboBox->setMapUnitScale( settingList.at( 0 ).lineSizeScale ); + + if ( settingList.at( 0 ).labelPlacementMethod == QgsDiagramSettings::Height ) { mLabelPlacementComboBox->setCurrentIndex( 0 ); } @@ -388,13 +370,13 @@ void QgsDiagramProperties::syncToLayer() mLabelPlacementComboBox->setCurrentIndex( 1 ); } - if ( diagramSettings.paintEffect() ) - mPaintEffect.reset( diagramSettings.paintEffect()->clone() ); + if ( settingList.at( 0 ).paintEffect() ) + mPaintEffect.reset( settingList.at( 0 ).paintEffect()->clone() ); - mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( diagramSettings.rotationOffset ) ); - mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( diagramSettings.direction() ) ); + mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( settingList.at( 0 ).rotationOffset ) ); + mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( settingList.at( 0 ).direction() ) ); - switch ( diagramSettings.diagramOrientation ) + switch ( settingList.at( 0 ).diagramOrientation ) { case QgsDiagramSettings::Left: mOrientationLeftButton->setChecked( true ); @@ -413,22 +395,22 @@ void QgsDiagramProperties::syncToLayer() break; } - mBarWidthSpinBox->setValue( diagramSettings.barWidth ); - mBarSpacingSpinBox->setValue( diagramSettings.spacing() ); - mBarSpacingUnitComboBox->setUnit( diagramSettings.spacingUnit() ); - mBarSpacingUnitComboBox->setMapUnitScale( diagramSettings.spacingMapUnitScale() ); + mBarWidthSpinBox->setValue( settingList.at( 0 ).barWidth ); + mBarSpacingSpinBox->setValue( settingList.at( 0 ).spacing() ); + mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() ); + mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() ); - mShowAxisGroupBox->setChecked( diagramSettings.showAxis() ); - if ( diagramSettings.axisLineSymbol() ) - mAxisLineStyleButton->setSymbol( diagramSettings.axisLineSymbol()->clone() ); + mShowAxisGroupBox->setChecked( settingList.at( 0 ).showAxis() ); + if ( settingList.at( 0 ).axisLineSymbol() ) + mAxisLineStyleButton->setSymbol( settingList.at( 0 ).axisLineSymbol()->clone() ); - mIncreaseSmallDiagramsCheck->setChecked( diagramSettings.minimumSize != 0 ); + mIncreaseSmallDiagramsCheck->setChecked( settingList.at( 0 ).minimumSize != 0 ); mIncreaseMinimumSizeSpinBox->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() ); mIncreaseMinimumSizeLabel->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() ); - mIncreaseMinimumSizeSpinBox->setValue( diagramSettings.minimumSize ); + mIncreaseMinimumSizeSpinBox->setValue( settingList.at( 0 ).minimumSize ); - if ( diagramSettings.scaleByArea ) + if ( settingList.at( 0 ).scaleByArea ) { mScaleDependencyComboBox->setCurrentIndex( 0 ); } @@ -437,9 +419,9 @@ void QgsDiagramProperties::syncToLayer() mScaleDependencyComboBox->setCurrentIndex( 1 ); } - const QList< QColor > categoryColors = diagramSettings.categoryColors; - const QList< QString > categoryAttributes = diagramSettings.categoryAttributes; - const QList< QString > categoryLabels = diagramSettings.categoryLabels; + const QList< QColor > categoryColors = settingList.at( 0 ).categoryColors; + const QList< QString > categoryAttributes = settingList.at( 0 ).categoryAttributes; + const QList< QString > categoryLabels = settingList.at( 0 ).categoryLabels; QList< QString >::const_iterator catIt = categoryAttributes.constBegin(); QList< QColor >::const_iterator coIt = categoryColors.constBegin(); QList< QString >::const_iterator labIt = categoryLabels.constBegin(); @@ -524,17 +506,10 @@ void QgsDiagramProperties::syncToLayer() if ( dr->diagram() ) { - if ( stackedDiagram ) - { - mDiagramType = stackedDiagram->subDiagramType( mSubDiagramIndex ); - } - else - { - mDiagramType = dr->diagram()->diagramName(); - } + mDiagramType = dr->diagram()->diagramName(); mDiagramTypeComboBox->blockSignals( true ); - mDiagramTypeComboBox->setCurrentIndex( ( diagramSettingsSet && diagramSettings.enabled ) ? mDiagramTypeComboBox->findData( mDiagramType ) : 0 ); + mDiagramTypeComboBox->setCurrentIndex( ( settingList.at( 0 ).enabled ) ? mDiagramTypeComboBox->findData( mDiagramType ) : 0 ); mDiagramTypeComboBox->blockSignals( false ); //force a refresh of widget status to match diagram type mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() ); diff --git a/src/gui/vector/qgsdiagramproperties.h b/src/gui/vector/qgsdiagramproperties.h index 34b8bb2b606a..fbb4a43d0c89 100644 --- a/src/gui/vector/qgsdiagramproperties.h +++ b/src/gui/vector/qgsdiagramproperties.h @@ -49,7 +49,7 @@ class GUI_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr * * \since QGIS 3.16 */ - void syncToLayer(); + void syncToLayer( const QgsDiagramRenderer *dr = nullptr ); ~QgsDiagramProperties() override; @@ -83,13 +83,6 @@ class GUI_EXPORT QgsDiagramProperties : public QWidget, private Ui::QgsDiagramPr private: - /** - * Subdiagram position in a stacked diagram. - * If the diagram is not part of a stacked diagram its value is -1. - * Used to access corresponding diagram settings. - */ - int mSubDiagramIndex = -1; - QgsVectorLayer *mLayer = nullptr; //! Point placement button group QButtonGroup *mPlacePointBtnGrp = nullptr; diff --git a/src/gui/vector/qgsstackeddiagramproperties.cpp b/src/gui/vector/qgsstackeddiagramproperties.cpp index 142e867b87c5..8bdac8ff0b3d 100644 --- a/src/gui/vector/qgsstackeddiagramproperties.cpp +++ b/src/gui/vector/qgsstackeddiagramproperties.cpp @@ -101,7 +101,7 @@ void QgsStackedDiagramProperties::syncToLayer() if ( dr && dr->diagram() ) { - if ( dr->diagram()->diagramName() == DIAGRAM_NAME_STACKED ) + if ( dr->rendererName() == QStringLiteral( "Stacked" ) ) { mDiagramTypeComboBox->blockSignals( true ); mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( QgsDiagramLayerSettings::Stacked ) ); @@ -114,23 +114,27 @@ void QgsStackedDiagramProperties::syncToLayer() mStackedDiagramSpacingSpinBox->setValue( settingList.at( 0 ).stackedDiagramSpacing() ); mStackedDiagramSpacingUnitComboBox->setUnit( settingList.at( 0 ).stackedDiagramSpacingUnit() ); - // Create as many tabs as necessary - const QgsStackedDiagram *stackedDiagram = dynamic_cast< const QgsStackedDiagram *>( dr->diagram() ); - const int subDiagramCount = stackedDiagram->subDiagramCount(); - while ( mSubDiagramsTabWidget->count() < subDiagramCount ) + // Create/remove as many tabs as necessary + const QgsStackedDiagramRenderer *stackedDiagramRenderer = static_cast< const QgsStackedDiagramRenderer * >( dr ); + const int rendererCount = stackedDiagramRenderer->rendererCount(); + while ( mSubDiagramsTabWidget->count() < rendererCount ) { addSubDiagram(); } + while ( mSubDiagramsTabWidget->count() > rendererCount ) + { + mSubDiagramsTabWidget->setCurrentIndex( mSubDiagramsTabWidget->count() - 1 ); + removeSubDiagram(); + } - // Call subdiagrams' syncToLayer with the corresponding subdiagram index + // Call subdiagrams' syncToLayer with the corresponding rendering object for ( int i = 0; i < mSubDiagramsTabWidget->count(); i++ ) { QgsDiagramProperties *diagramProperties = static_cast( mSubDiagramsTabWidget->widget( i ) ); - diagramProperties->mSubDiagramIndex = i; - diagramProperties->syncToLayer(); + diagramProperties->syncToLayer( stackedDiagramRenderer->renderer( i ) ); } } - else + else // Single diagram { mDiagramTypeComboBox->blockSignals( true ); mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( QgsDiagramLayerSettings::Single ) ); @@ -143,10 +147,10 @@ void QgsStackedDiagramProperties::syncToLayer() static_cast( mSubDiagramsTabWidget->widget( 0 ) )->syncToLayer(); } } - else + else // No Diagram { mDiagramTypeComboBox->blockSignals( true ); - mDiagramTypeComboBox->setCurrentIndex( 0 ); // No Diagram + mDiagramTypeComboBox->setCurrentIndex( 0 ); mDiagramTypeComboBox->blockSignals( false ); //force a refresh of widget status to match diagram type mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() ); @@ -187,16 +191,15 @@ void QgsStackedDiagramProperties::apply() } else // Stacked diagram { - // TODO: Validate that we have at least 2 diagrams - - // Create DiagramSetings for the StackedDiagram - std::unique_ptr< QgsDiagramSettings> ds = std::make_unique(); + // Create diagram settings for the StackedDiagram + std::unique_ptr< QgsDiagramSettings> ds = std::make_unique< QgsDiagramSettings >(); ds->stackedDiagramMode = static_cast( mStackedDiagramModeComboBox->currentData().toInt() ); ds->setStackedDiagramSpacingUnit( mStackedDiagramSpacingUnitComboBox->unit() ); ds->setStackedDiagramSpacing( mStackedDiagramSpacingSpinBox->value() ); - // Add subdiagrams with their DiagramSettings to StackedDiagram - std::unique_ptr< QgsStackedDiagram > stackedDiagram = std::make_unique< QgsStackedDiagram >(); + // Create diagram renderer for the StackedDiagram + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); // Get DiagramSettings from each subdiagram for ( int i = 0; i < mSubDiagramsTabWidget->count(); i++ ) @@ -207,6 +210,8 @@ void QgsStackedDiagramProperties::apply() ds->categoryLabels += ds1->categoryLabels; ds->categoryColors += ds1->categoryColors; + std::unique_ptr< QgsDiagramRenderer > dr1 = diagramProperties->createRendererBaseInfo( *ds1 ); + std::unique_ptr< QgsDiagram > diagram; if ( diagramProperties->mDiagramType == DIAGRAM_NAME_TEXT ) @@ -225,18 +230,16 @@ void QgsStackedDiagramProperties::apply() { diagram = std::make_unique< QgsHistogramDiagram >(); } - stackedDiagram->addSubDiagram( diagram.release(), ds1.release() ); - } - // Get first diagram to configure some stacked diagram settings from it - QgsDiagramProperties *firstDiagramProperties = static_cast( mSubDiagramsTabWidget->widget( 0 ) ); + dr1->setDiagram( diagram.release() ); + dr->addRenderer( dr1.release() ); + } - // Create DiagramRenderer using info from first diagram and setting Stacked Diagram and the stacked diagram's DiagramSettings - std::unique_ptr< QgsDiagramRenderer > renderer = firstDiagramProperties->createRendererBaseInfo( *ds ); - renderer->setDiagram( stackedDiagram.release() ); - mLayer->setDiagramRenderer( renderer.release() ); + dr->setDiagramSettings( *ds ); + mLayer->setDiagramRenderer( dr ); // Create DiagramLayerSettings from first diagram + QgsDiagramProperties *firstDiagramProperties = static_cast< QgsDiagramProperties * >( mSubDiagramsTabWidget->widget( 0 ) ); QgsDiagramLayerSettings dls = firstDiagramProperties->createDiagramLayerSettings(); mLayer->setDiagramLayerSettings( dls ); diff --git a/src/gui/vector/qgsstackeddiagramproperties.h b/src/gui/vector/qgsstackeddiagramproperties.h index 769cb4c43e4d..8fb3e4d3e868 100644 --- a/src/gui/vector/qgsstackeddiagramproperties.h +++ b/src/gui/vector/qgsstackeddiagramproperties.h @@ -63,8 +63,6 @@ class GUI_EXPORT QgsStackedDiagramProperties : public QWidget, private Ui::QgsSt /** * Adds a diagram tab to the current QgsStackedDiagramProperties. - * - * \since QGIS 3.40 */ void addSubDiagram(); @@ -72,15 +70,12 @@ class GUI_EXPORT QgsStackedDiagramProperties : public QWidget, private Ui::QgsSt * Removes a diagram tab from the current QgsStackedDiagramProperties. * Diagram tabs are removed only if the tab count is greeater than 2. * Tab texts are adjusted after tab removal, to keep sequential order. - * - * \since QGIS 3.40 */ void removeSubDiagram(); private: QgsVectorLayer *mLayer = nullptr; QgsMapCanvas *mMapCanvas = nullptr; - }; #endif // QGSSTACKEDDIAGRAMPROPERTIES_H diff --git a/tests/code_layout/acceptable_missing_doc.py b/tests/code_layout/acceptable_missing_doc.py index af590100965a..3ae65bc61dbb 100644 --- a/tests/code_layout/acceptable_missing_doc.py +++ b/tests/code_layout/acceptable_missing_doc.py @@ -135,6 +135,7 @@ "pal::PointSet": ["getCentroid(double &px, double &py, bool forceInside=false) const", "PointSet(double x, double y)", "invalidateGeos() const", "getGeosType() const", "PointSet(int nbPoints, double *x, double *y)", "getNumPoints() const", "deleteCoords()", "preparedGeom() const", "PointSet(const PointSet &ps)", "createGeosGeom() const"], "QgsSimpleFillSymbolLayer": ["createFromSld(QDomElement &element)", "setBrushStyle(Qt::BrushStyle style)", "setStrokeWidth(double strokeWidth)", "strokeWidth() const", "brushStyle() const", "strokeWidthMapUnitScale() const", "strokeStyle() const", "setPenJoinStyle(Qt::PenJoinStyle style)", "QgsSimpleFillSymbolLayer(const QColor &color=DEFAULT_SIMPLEFILL_COLOR, Qt::BrushStyle style=DEFAULT_SIMPLEFILL_STYLE, const QColor &strokeColor=DEFAULT_SIMPLEFILL_BORDERCOLOR, Qt::PenStyle strokeStyle=DEFAULT_SIMPLEFILL_BORDERSTYLE, double strokeWidth=DEFAULT_SIMPLEFILL_BORDERWIDTH, Qt::PenJoinStyle penJoinStyle=DEFAULT_SIMPLEFILL_JOINSTYLE)", "setStrokeWidthMapUnitScale(const QgsMapUnitScale &scale)", "penJoinStyle() const", "setStrokeStyle(Qt::PenStyle strokeStyle)"], "QgsSingleCategoryDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"], + "QgsStackedDiagramRenderer": ["setDiagramSettings(const QgsDiagramSettings &s)"], "QgsPointDisplacementRendererWidget": ["QgsPointDisplacementRendererWidget(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)", "create(QgsVectorLayer *layer, QgsStyle *style, QgsFeatureRenderer *renderer)"], "QgsSingleBandGrayRendererWidget": ["create(QgsRasterLayer *layer, const QgsRectangle &extent)", "QgsSingleBandGrayRendererWidget(QgsRasterLayer *layer, const QgsRectangle &extent=QgsRectangle())"], "QgsLayerTreeModel": ["nodeWillRemoveChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "disconnectFromLayers(QgsLayerTreeGroup *parentGroup)", "connectToLayers(QgsLayerTreeGroup *parentGroup)", "nodeLayerWillBeUnloaded()", "legendInvalidateMapBasedData()", "nodeCustomPropertyChanged(QgsLayerTreeNode *node, const QString &key)", "legendNodeData(QgsLayerTreeModelLegendNode *node, int role) const", "legendCleanup()", "Flag", "iconGroup()", "disconnectFromRootNode()", "layerNeedsUpdate()", "addLegendToLayer(QgsLayerTreeLayer *nodeL)", "nodeVisibilityChanged(QgsLayerTreeNode *node)", "layerLegendChanged()", "legendRootRowCount(QgsLayerTreeLayer *nL) const", "removeLegendFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendNodeRowCount(QgsLayerTreeModelLegendNode *node) const", "legendNodeDataChanged()", "connectToRootNode()", "legendNodeFlags(QgsLayerTreeModelLegendNode *node) const", "indexOfParentLayerTreeNode(QgsLayerTreeNode *parentNode) const", "nodeLayerLoaded()", "nodeWillAddChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "nodeRemovedChildren()", "legendRootIndex(int row, int column, QgsLayerTreeLayer *nL) const", "connectToLayer(QgsLayerTreeLayer *nodeLayer)", "legendIconEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "nodeAddedChildren(QgsLayerTreeNode *node, int indexFrom, int indexTo)", "legendNodeIndex(int row, int column, QgsLayerTreeModelLegendNode *node) const", "invalidateLegendMapBasedData()", "disconnectFromLayer(QgsLayerTreeLayer *nodeLayer)", "legendEmbeddedInParent(QgsLayerTreeLayer *nodeLayer) const", "legendParent(QgsLayerTreeModelLegendNode *legendNode) const"], diff --git a/tests/src/core/testqgsstackeddiagram.cpp b/tests/src/core/testqgsstackeddiagram.cpp index c80631949436..f39a14d4dd54 100644 --- a/tests/src/core/testqgsstackeddiagram.cpp +++ b/tests/src/core/testqgsstackeddiagram.cpp @@ -13,17 +13,6 @@ * * ***************************************************************************/ #include "qgstest.h" -#include -#include -#include -#include -#include -#include -#include -#include - -//qgis includes... -// #include #include "diagram/qgspiediagram.h" #include "diagram/qgstextdiagram.h" #include "diagram/qgsstackedbardiagram.h" @@ -35,12 +24,18 @@ #include "qgsapplication.h" #include "qgsrenderer.h" #include "qgssinglesymbolrenderer.h" -//qgis test includes #include "qgsproject.h" -#include "qgsshadoweffect.h" -#include "qgslinesymbol.h" #include "qgsmarkersymbol.h" +#include +#include +#include +#include +#include +#include +#include +#include + /** * \ingroup UnitTests * Unit tests for stacked diagrams @@ -140,6 +135,15 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 0; ds1.diagramOrientation = QgsDiagramSettings::Left; + QgsLinearlyInterpolatedDiagramRenderer *dr1 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr1->setDiagram( new QgsHistogramDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->setLowerValue( 0.0 ); + dr1->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr1->setUpperValue( 15000 ); + dr1->setUpperSize( QSizeF( 20, 20 ) ); + //dr1->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + // Histogram 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -162,24 +166,26 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 0; ds2.diagramOrientation = QgsDiagramSettings::Right; + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + //dr2->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Horizontal; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Pixels ); ds.setStackedDiagramSpacing( 0 ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds2 ); - - QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer(); - dr->setLowerValue( 0.0 ); - dr->setLowerSize( QSizeF( 0.0, 0.0 ) ); - dr->setUpperValue( 15000 ); - dr->setUpperSize( QSizeF( 20, 20 ) ); - dr->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -218,6 +224,15 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 0; ds1.diagramOrientation = QgsDiagramSettings::Up; + QgsLinearlyInterpolatedDiagramRenderer *dr1 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr1->setDiagram( new QgsHistogramDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->setLowerValue( 0.0 ); + dr1->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr1->setUpperValue( 15000 ); + dr1->setUpperSize( QSizeF( 20, 20 ) ); + //dr1->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + // Histogram 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -240,24 +255,26 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 0; ds2.diagramOrientation = QgsDiagramSettings::Down; + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + //dr2->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Vertical; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Pixels ); ds.setStackedDiagramSpacing( 0 ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds2 ); - - QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer(); - dr->setLowerValue( 0.0 ); - dr->setLowerSize( QSizeF( 0.0, 0.0 ) ); - dr->setUpperValue( 15000 ); - dr->setUpperSize( QSizeF( 20, 20 ) ); - dr->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -296,6 +313,15 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 0; ds1.diagramOrientation = QgsDiagramSettings::Up; + QgsLinearlyInterpolatedDiagramRenderer *dr1 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr1->setDiagram( new QgsHistogramDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->setLowerValue( 0.0 ); + dr1->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr1->setUpperValue( 15000 ); + dr1->setUpperSize( QSizeF( 20, 20 ) ); + //dr1->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + // Histogram 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -318,24 +344,26 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 0; ds2.diagramOrientation = QgsDiagramSettings::Down; + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + //dr2->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Vertical; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); ds.setStackedDiagramSpacing( 8 ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds2 ); - - QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer(); - dr->setLowerValue( 0.0 ); - dr->setLowerSize( QSizeF( 0.0, 0.0 ) ); - dr->setUpperValue( 15000 ); - dr->setUpperSize( QSizeF( 20, 20 ) ); - dr->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -376,6 +404,15 @@ class TestQgsStackedDiagram : public QgsTest ds1.setSpacing( 8 ); ds1.setSpacingUnit( Qgis::RenderUnit::Points ); + QgsLinearlyInterpolatedDiagramRenderer *dr1 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr1->setDiagram( new QgsHistogramDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->setLowerValue( 0.0 ); + dr1->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr1->setUpperValue( 15000 ); + dr1->setUpperSize( QSizeF( 20, 20 ) ); + //dr1->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + // Histogram 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -400,24 +437,26 @@ class TestQgsStackedDiagram : public QgsTest ds2.setSpacing( 8 ); ds2.setSpacingUnit( Qgis::RenderUnit::Points ); + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + //dr2->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Horizontal; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); ds.setStackedDiagramSpacing( 8 ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds2 ); - - QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer(); - dr->setLowerValue( 0.0 ); - dr->setLowerSize( QSizeF( 0.0, 0.0 ) ); - dr->setUpperValue( 15000 ); - dr->setUpperSize( QSizeF( 20, 20 ) ); - dr->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -458,6 +497,15 @@ class TestQgsStackedDiagram : public QgsTest ds1.setSpacing( 0 ); ds1.setSpacingUnit( Qgis::RenderUnit::Points ); + QgsLinearlyInterpolatedDiagramRenderer *dr1 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr1->setDiagram( new QgsHistogramDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->setLowerValue( 0.0 ); + dr1->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr1->setUpperValue( 15000 ); + dr1->setUpperSize( QSizeF( 20, 20 ) ); + //dr1->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + // Histogram 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -482,24 +530,26 @@ class TestQgsStackedDiagram : public QgsTest ds2.setSpacing( 0 ); ds2.setSpacingUnit( Qgis::RenderUnit::Points ); + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + //dr2->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Horizontal; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); ds.setStackedDiagramSpacing( 8 ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsHistogramDiagram(), &ds2 ); - - QgsLinearlyInterpolatedDiagramRenderer *dr = new QgsLinearlyInterpolatedDiagramRenderer(); - dr->setLowerValue( 0.0 ); - dr->setLowerSize( QSizeF( 0.0, 0.0 ) ); - dr->setUpperValue( 15000 ); - dr->setUpperSize( QSizeF( 20, 20 ) ); - dr->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -630,6 +680,10 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 270; ds1.setDirection( QgsDiagramSettings::Counterclockwise ); + QgsSingleCategoryDiagramRenderer *dr1 = new QgsSingleCategoryDiagramRenderer(); + dr1->setDiagram( new QgsPieDiagram() ); + dr1->setDiagramSettings( ds1 ); + // Pie 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -652,17 +706,19 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 270; ds2.setDirection( QgsDiagramSettings::Counterclockwise ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds2 ); + QgsSingleCategoryDiagramRenderer *dr2 = new QgsSingleCategoryDiagramRenderer(); + dr2->setDiagram( new QgsPieDiagram() ); + dr2->setDiagramSettings( ds2 ); QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Vertical; ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; - QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer(); - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -701,6 +757,10 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 270; ds1.setDirection( QgsDiagramSettings::Counterclockwise ); + QgsSingleCategoryDiagramRenderer *dr1 = new QgsSingleCategoryDiagramRenderer(); + dr1->setDiagram( new QgsPieDiagram() ); + dr1->setDiagramSettings( ds1 ); + // Pie 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -723,9 +783,9 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 270; ds2.setDirection( QgsDiagramSettings::Counterclockwise ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds2 ); + QgsSingleCategoryDiagramRenderer *dr2 = new QgsSingleCategoryDiagramRenderer(); + dr2->setDiagram( new QgsPieDiagram() ); + dr2->setDiagramSettings( ds2 ); QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Vertical; @@ -733,9 +793,11 @@ class TestQgsStackedDiagram : public QgsTest ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); ds.setStackedDiagramSpacing( 8 ); - QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer(); - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -774,6 +836,10 @@ class TestQgsStackedDiagram : public QgsTest ds1.rotationOffset = 270; ds1.setDirection( QgsDiagramSettings::Counterclockwise ); + QgsSingleCategoryDiagramRenderer *dr1 = new QgsSingleCategoryDiagramRenderer(); + dr1->setDiagram( new QgsPieDiagram() ); + dr1->setDiagramSettings( ds1 ); + // Pie 2 QgsDiagramSettings ds2; col1 = Qt::blue; @@ -796,9 +862,9 @@ class TestQgsStackedDiagram : public QgsTest ds2.rotationOffset = 270; ds2.setDirection( QgsDiagramSettings::Counterclockwise ); - QgsStackedDiagram *stackedDiagram = new QgsStackedDiagram(); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds1 ); - stackedDiagram->addSubDiagram( new QgsPieDiagram(), &ds2 ); + QgsSingleCategoryDiagramRenderer *dr2 = new QgsSingleCategoryDiagramRenderer(); + dr2->setDiagram( new QgsPieDiagram() ); + dr2->setDiagramSettings( ds2 ); QgsDiagramSettings ds; ds.stackedDiagramMode = QgsDiagramSettings::Horizontal; @@ -806,9 +872,11 @@ class TestQgsStackedDiagram : public QgsTest ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); ds.setStackedDiagramSpacing( 8 ); - QgsSingleCategoryDiagramRenderer *dr = new QgsSingleCategoryDiagramRenderer(); - dr->setDiagram( stackedDiagram ); + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); mPointsLayer->setDiagramRenderer( dr ); QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); @@ -903,6 +971,227 @@ class TestQgsStackedDiagram : public QgsTest QGSVERIFYRENDERMAPSETTINGSCHECK( "stackedwomenpie", "stackedwomenpie", *mMapSettings, 200, 15 ); } + void testStackedPieHistogram() + { + // Pie + QgsDiagramSettings ds1; + QColor col1 = Qt::blue; + QColor col2 = Qt::red; + QColor col3 = Qt::yellow; + QColor col4 = Qt::green; + col1.setAlphaF( 0.5 ); + col2.setAlphaF( 0.5 ); + col3.setAlphaF( 0.5 ); + col4.setAlphaF( 0.5 ); + ds1.categoryColors = QList() << col1 << col2 << col3 << col4; + ds1.categoryAttributes = QList() << QStringLiteral( "\"maennlich_ab_65\"" ) << QStringLiteral( "\"maennlich_18_64\"" ) << QStringLiteral( "\"maennlich_6_17\"" ) << QStringLiteral( "\"maennlich_unter_6\"" ); //#spellok + ds1.minimumScale = -1; + ds1.maximumScale = -1; + ds1.minimumSize = 0; + ds1.penColor = Qt::black; + ds1.penWidth = .5; + ds1.sizeType = Qgis::RenderUnit::Millimeters; + ds1.size = QSizeF( 10, 10 ); + ds1.rotationOffset = 270; + ds1.setDirection( QgsDiagramSettings::Counterclockwise ); + + QgsSingleCategoryDiagramRenderer *dr1 = new QgsSingleCategoryDiagramRenderer(); + dr1->setDiagram( new QgsPieDiagram() ); + dr1->setDiagramSettings( ds1 ); + + // Histogram + QgsDiagramSettings ds2; + col1 = Qt::blue; + col2 = Qt::red; + col3 = Qt::yellow; + col4 = Qt::green; + col1.setAlphaF( 0.5 ); + col2.setAlphaF( 0.5 ); + col3.setAlphaF( 0.5 ); + col4.setAlphaF( 0.5 ); + ds2.categoryColors = QList() << col1 << col2 << col3 << col4; + ds2.categoryAttributes = QList() << QStringLiteral( "\"weiblich_ab_65\"" ) << QStringLiteral( "\"weiblich_18_64\"" ) << QStringLiteral( "\"weiblich_6_17\"" ) << QStringLiteral( "\"weiblich_unter_6\"" ); //#spellok + ds2.minimumScale = -1; + ds2.maximumScale = -1; + ds2.minimumSize = 0; + ds2.penColor = Qt::black; + ds2.penWidth = .5; + ds2.scaleByArea = true; + ds2.sizeType = Qgis::RenderUnit::Millimeters; + ds2.rotationOffset = 0; + ds2.diagramOrientation = QgsDiagramSettings::Right; + + QgsLinearlyInterpolatedDiagramRenderer *dr2 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr2->setLowerValue( 0.0 ); + dr2->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr2->setUpperValue( 15000 ); + dr2->setUpperSize( QSizeF( 20, 20 ) ); + dr2->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + dr2->setDiagram( new QgsHistogramDiagram() ); + dr2->setDiagramSettings( ds2 ); + + QgsDiagramSettings ds; + ds.stackedDiagramMode = QgsDiagramSettings::Horizontal; + ds.categoryAttributes = ds1.categoryAttributes + ds2.categoryAttributes; + ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); + ds.setStackedDiagramSpacing( 8 ); + + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); + dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); + mPointsLayer->setDiagramRenderer( dr ); + + QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); + dls.setPlacement( QgsDiagramLayerSettings::OverPoint ); + dls.setShowAllDiagrams( true ); + mPointsLayer->setDiagramLayerSettings( dls ); + + const QgsRectangle extent( 9.7, 53.5, 9.95, 53.6 ); + mMapSettings->setExtent( extent ); + mMapSettings->setFlag( Qgis::MapSettingsFlag::ForceVectorOutput ); + mMapSettings->setOutputDpi( 96 ); + QGSVERIFYRENDERMAPSETTINGSCHECK( "stackedpiehistogram", "stackedpiehistogram", *mMapSettings, 200, 15 ); + } + + void testStackedDiagramsNested() + { + // Nested stacked histograms (just because we can :)) + // 1 vertically stacked diagram: + // Above: + // + Horizontally stacked diagram + // + 2 histograms + // Below: + // + 1 pie + + // Histogram 1 + QgsDiagramSettings ds11; + QColor col1 = Qt::blue; + QColor col2 = Qt::red; + QColor col3 = Qt::yellow; + QColor col4 = Qt::green; + col1.setAlphaF( 0.5 ); + col2.setAlphaF( 0.5 ); + col3.setAlphaF( 0.5 ); + col4.setAlphaF( 0.5 ); + ds11.categoryColors = QList() << col1 << col2 << col3 << col4; + ds11.categoryAttributes = QList() << QStringLiteral( "\"maennlich_ab_65\"" ) << QStringLiteral( "\"maennlich_18_64\"" ) << QStringLiteral( "\"maennlich_6_17\"" ) << QStringLiteral( "\"maennlich_unter_6\"" ); //#spellok + ds11.minimumScale = -1; + ds11.maximumScale = -1; + ds11.minimumSize = 0; + ds11.penColor = Qt::black; + ds11.penWidth = .5; + ds11.scaleByArea = true; + ds11.sizeType = Qgis::RenderUnit::Millimeters; + ds11.barWidth = 3; + ds11.rotationOffset = 0; + ds11.diagramOrientation = QgsDiagramSettings::Left; + + QgsLinearlyInterpolatedDiagramRenderer *dr11 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr11->setDiagram( new QgsHistogramDiagram() ); + dr11->setDiagramSettings( ds11 ); + dr11->setLowerValue( 0.0 ); + dr11->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr11->setUpperValue( 15000 ); + dr11->setUpperSize( QSizeF( 20, 20 ) ); + //dr11->setClassificationField( QStringLiteral( "max(\"maennlich_18_64\", \"maennlich_ab_65\", \"maennlich_6_17\", \"maennlich_unter_6\")" ) ); //#spellok + + // Histogram 2 + QgsDiagramSettings ds12; + col1 = Qt::blue; + col2 = Qt::red; + col3 = Qt::yellow; + col4 = Qt::green; + col1.setAlphaF( 0.5 ); + col2.setAlphaF( 0.5 ); + col3.setAlphaF( 0.5 ); + col4.setAlphaF( 0.5 ); + ds12.categoryColors = QList() << col1 << col2 << col3 << col4; + ds12.categoryAttributes = QList() << QStringLiteral( "\"weiblich_ab_65\"" ) << QStringLiteral( "\"weiblich_18_64\"" ) << QStringLiteral( "\"weiblich_6_17\"" ) << QStringLiteral( "\"weiblich_unter_6\"" ); //#spellok + ds12.minimumScale = -1; + ds12.maximumScale = -1; + ds12.minimumSize = 0; + ds12.penColor = Qt::black; + ds12.penWidth = .5; + ds12.scaleByArea = true; + ds12.barWidth = 3; + ds12.sizeType = Qgis::RenderUnit::Millimeters; + ds12.rotationOffset = 0; + ds12.diagramOrientation = QgsDiagramSettings::Right; + + QgsLinearlyInterpolatedDiagramRenderer *dr12 = new QgsLinearlyInterpolatedDiagramRenderer(); + dr12->setDiagram( new QgsHistogramDiagram() ); + dr12->setDiagramSettings( ds12 ); + dr12->setLowerValue( 0.0 ); + dr12->setLowerSize( QSizeF( 0.0, 0.0 ) ); + dr12->setUpperValue( 15000 ); + dr12->setUpperSize( QSizeF( 20, 20 ) ); + //dr12->setClassificationField( QStringLiteral( "max(\"weiblich_unter_6\", \"weiblich_6_17\", \"weiblich_18_64\", \"weiblich_ab_65\")" ) ); //#spellok + + QgsDiagramSettings ds1; + ds1.stackedDiagramMode = QgsDiagramSettings::Horizontal; + ds1.categoryAttributes = ds11.categoryAttributes + ds12.categoryAttributes; + ds1.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Pixels ); + ds1.setStackedDiagramSpacing( 0 ); + + QgsStackedDiagramRenderer *dr1 = new QgsStackedDiagramRenderer(); + dr1->setDiagram( new QgsStackedDiagram() ); + dr1->setDiagramSettings( ds1 ); + dr1->addRenderer( dr11 ); + dr1->addRenderer( dr12 ); + + // Pie + QgsDiagramSettings ds2; + col1 = Qt::blue; + col2 = Qt::red; + col3 = Qt::yellow; + col4 = Qt::green; + col1.setAlphaF( 0.5 ); + col2.setAlphaF( 0.5 ); + col3.setAlphaF( 0.5 ); + col4.setAlphaF( 0.5 ); + ds2.categoryColors = QList() << col1 << col2 << col3 << col4; + ds2.categoryAttributes = QList() << QStringLiteral( "\"gesamt_ab_65\"" ) << QStringLiteral( "\"gesamt_18_64\"" ) << QStringLiteral( "\"gesamt_6_17\"" ) << QStringLiteral( "\"gesamt_unter_6\"" ); //#spellok + ds2.minimumScale = -1; + ds2.maximumScale = -1; + ds2.minimumSize = 0; + ds2.penColor = Qt::black; + ds2.penWidth = .5; + ds2.sizeType = Qgis::RenderUnit::Millimeters; + ds2.size = QSizeF( 10, 10 ); + ds2.rotationOffset = 270; + ds2.setDirection( QgsDiagramSettings::Counterclockwise ); + + QgsSingleCategoryDiagramRenderer *dr2 = new QgsSingleCategoryDiagramRenderer(); + dr2->setDiagram( new QgsPieDiagram() ); + dr2->setDiagramSettings( ds2 ); + + QgsDiagramSettings ds; + ds.stackedDiagramMode = QgsDiagramSettings::Vertical; + ds.categoryAttributes = ds11.categoryAttributes + ds12.categoryAttributes + ds2.categoryAttributes; + ds.setStackedDiagramSpacingUnit( Qgis::RenderUnit::Points ); + ds.setStackedDiagramSpacing( 4 ); + + QgsStackedDiagramRenderer *dr = new QgsStackedDiagramRenderer(); + dr->setDiagram( new QgsStackedDiagram() ); + dr->setDiagramSettings( ds ); + dr->addRenderer( dr1 ); + dr->addRenderer( dr2 ); + mPointsLayer->setDiagramRenderer( dr ); + + QgsDiagramLayerSettings dls = QgsDiagramLayerSettings(); + dls.setPlacement( QgsDiagramLayerSettings::OverPoint ); + dls.setShowAllDiagrams( true ); + mPointsLayer->setDiagramLayerSettings( dls ); + + const QgsRectangle extent( 9.7, 53.5, 9.95, 53.6 ); + mMapSettings->setExtent( extent ); + mMapSettings->setFlag( Qgis::MapSettingsFlag::ForceVectorOutput ); + mMapSettings->setOutputDpi( 96 ); + QGSVERIFYRENDERMAPSETTINGSCHECK( "stackeddiagramsnested", "stackeddiagramsnested", *mMapSettings, 200, 15 ); + } + }; diff --git a/tests/testdata/control_images/stackeddiagrams/expected_stackeddiagramsnested/expected_stackeddiagramsnested.png b/tests/testdata/control_images/stackeddiagrams/expected_stackeddiagramsnested/expected_stackeddiagramsnested.png new file mode 100644 index 000000000000..3d089da21a46 Binary files /dev/null and b/tests/testdata/control_images/stackeddiagrams/expected_stackeddiagramsnested/expected_stackeddiagramsnested.png differ diff --git a/tests/testdata/control_images/stackeddiagrams/expected_stackedpiehistogram/expected_stackedpiehistogram.png b/tests/testdata/control_images/stackeddiagrams/expected_stackedpiehistogram/expected_stackedpiehistogram.png new file mode 100644 index 000000000000..1939a1bc513e Binary files /dev/null and b/tests/testdata/control_images/stackeddiagrams/expected_stackedpiehistogram/expected_stackedpiehistogram.png differ