Skip to content

Commit

Permalink
Deprecate QgsLegendRenderer methods which use raw QPainter and force …
Browse files Browse the repository at this point in the history
…use of QgsRenderContext
  • Loading branch information
nyalldawson committed Apr 28, 2020
1 parent 2d74769 commit 38dfcdf
Show file tree
Hide file tree
Showing 20 changed files with 432 additions and 283 deletions.
5 changes: 4 additions & 1 deletion python/core/auto_generated/qgslegendrenderer.sip.in
Expand Up @@ -65,10 +65,13 @@ If the returned size is null, the legend will be drawn with the minimum possible
.. seealso:: :py:func:`setLegendSize`
%End

void drawLegend( QPainter *painter );
void drawLegend( QPainter *painter ) /Deprecated/;
%Docstring
Draws the legend with given ``painter``. The legend will occupy the area reported in legendSize().
The ``painter`` should be scaled beforehand so that units correspond to millimeters.

.. deprecated::
Use the variant which accepts a QgsRenderContext instead.
%End

void drawLegend( QgsRenderContext &context );
Expand Down
117 changes: 104 additions & 13 deletions python/core/auto_generated/qgslegendsettings.sip.in
Expand Up @@ -28,7 +28,18 @@ in QgsLegendModel class.
QgsLegendSettings();

void setTitle( const QString &t );
%Docstring
Sets the title for the legend, which will be rendered above all legend items.

.. seealso:: :py:func:`title`
%End

QString title() const;
%Docstring
Returns the title for the legend, which will be rendered above all legend items.

.. seealso:: :py:func:`setTitle`
%End

Qt::AlignmentFlag titleAlignment() const;
%Docstring
Expand All @@ -44,17 +55,56 @@ Sets the ``alignment`` of the legend title.
.. seealso:: :py:func:`titleAlignment`
%End


QgsLegendStyle style( QgsLegendStyle::Style s ) const;
%Docstring
Returns style
Returns the style for a legend component.

.. seealso:: :py:func:`setStyle`
%End

void setStyle( QgsLegendStyle::Style s, const QgsLegendStyle &style );
%Docstring
Sets the ``style`` for a legend component.

.. seealso:: :py:func:`style`
%End

double boxSpace() const;
%Docstring
Returns the legend box space (in millimeters), which is the empty margin around the inside of the legend's
rectangle.

.. seealso:: :py:func:`setBoxSpace`
%End

void setBoxSpace( double s );
%Docstring
Sets the legend box space (in millimeters), which is the empty margin around the inside of the legend's
rectangle.

.. seealso:: :py:func:`boxSpace`
%End

void setWrapChar( const QString &t );
%Docstring
Sets a string to use as a wrapping character.

Whenever this string is encountered inside legend component text it will be automatically replaced with a new
line character.

.. seealso:: :py:func:`wrapChar`
%End

QString wrapChar() const;
%Docstring
Returns the string used as a wrapping character.

Whenever this string is encountered inside legend component text it will be automatically replaced with a new
line character.

.. seealso:: :py:func:`setWrapChar`
%End

double columnSpace() const;
void setColumnSpace( double s );
Expand Down Expand Up @@ -214,48 +264,89 @@ only drawn if drawRasterStroke() is ``True``.
double lineSpacing() const;
void setLineSpacing( double s );

double mmPerMapUnit() const;
void setMmPerMapUnit( double mmPerMapUnit );
double mmPerMapUnit() const /Deprecated/;
%Docstring

.. deprecated::
Use scale factor from render contexts instead.
%End

void setMmPerMapUnit( double mmPerMapUnit ) /Deprecated/;
%Docstring

.. deprecated::
Set scale factor on render contexts instead.
%End

bool useAdvancedEffects() const /Deprecated/;
%Docstring

.. deprecated::
Use flags from render contexts instead.
%End

void setUseAdvancedEffects( bool use ) /Deprecated/;
%Docstring

bool useAdvancedEffects() const;
void setUseAdvancedEffects( bool use );
.. deprecated::
Set flag on render contexts instead.
%End

double mapScale() const;
double mapScale() const /Deprecated/;
%Docstring
Returns the legend map scale.
The scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.

.. seealso:: :py:func:`setMapScale`

.. deprecated::
take this property from the render context instead
%End

void setMapScale( double scale );
void setMapScale( double scale ) /Deprecated/;
%Docstring
Sets the legend map ``scale``.
The ``scale`` value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.

.. seealso:: :py:func:`mapScale`

.. deprecated::
set this property on the render context instead
%End

double mapUnitsPerPixel() const;
double mapUnitsPerPixel() const /Deprecated/;
%Docstring
Returns the factor of map units per pixel for symbols with size given in map units calculated by dpi and mmPerMapUnit

.. seealso:: :py:func:`setMapUnitsPerPixel`

.. versionadded:: 3.8
.. deprecated::
take these properties on render contexts instead
%End

void setMapUnitsPerPixel( double mapUnitsPerPixel );
void setMapUnitsPerPixel( double mapUnitsPerPixel ) /Deprecated/;
%Docstring
Sets the mmPerMapUnit calculated by ``mapUnitsPerPixel`` mostly taken from the map settings.

.. seealso:: :py:func:`mapUnitsPerPixel`

.. versionadded:: 3.8
.. deprecated::
set these properties on render contexts instead
%End

int dpi() const;
void setDpi( int dpi );
int dpi() const /Deprecated/;
%Docstring

.. deprecated::
Take dpi from render contexts instead.
%End

void setDpi( int dpi ) /Deprecated/;
%Docstring

.. deprecated::
Set dpi on render contexts instead.
%End



Expand Down
4 changes: 2 additions & 2 deletions python/core/auto_generated/qgslegendstyle.sip.in
Expand Up @@ -105,14 +105,14 @@ Sets the alignment for the legend component.
.. versionadded:: 3.10
%End

void writeXml( const QString &name, QDomElement &elem, QDomDocument &doc ) const;
void writeXml( const QString &name, QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() ) const;
%Docstring
Writes the component's style definition to an XML element.

.. seealso:: :py:func:`readXml`
%End

void readXml( const QDomElement &elem, const QDomDocument &doc );
void readXml( const QDomElement &elem, const QDomDocument &doc, const QgsReadWriteContext &context = QgsReadWriteContext() );
%Docstring
Reads the component's style definition from an XML element.

Expand Down
64 changes: 46 additions & 18 deletions src/core/layertree/qgslayertreemodellegendnode.cpp
Expand Up @@ -532,10 +532,13 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
else
{
tempRenderContext = qgis::make_unique< QgsRenderContext >();
// QGIS 4.0 - make ItemContext compulsory, so we don't have to construct temporary render contexts here
Q_NOWARN_DEPRECATED_PUSH
tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
tempRenderContext->setRendererScale( settings.mapScale() );
tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
Q_NOWARN_DEPRECATED_POP
tempRenderContext->setForceVectorOutput( true );
tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );

Expand Down Expand Up @@ -599,7 +602,11 @@ QSizeF QgsSymbolLegendNode::drawSymbol( const QgsLegendSettings &settings, ItemC
}

p->scale( 1.0 / dotsPerMM, 1.0 / dotsPerMM );
if ( opacity != 255 && settings.useAdvancedEffects() )
Q_NOWARN_DEPRECATED_PUSH
// QGIS 4.0 -- ctx->context will be mandatory
const bool useAdvancedEffects = ctx->context ? ctx->context->flags() & QgsRenderContext::UseAdvancedEffects : settings.useAdvancedEffects();
Q_NOWARN_DEPRECATED_POP
if ( opacity != 255 && useAdvancedEffects )
{
const int maxBleed = static_cast< int >( std::ceil( QgsSymbolLayerUtils::estimateMaxSymbolBleed( s, *context ) ) );

Expand Down Expand Up @@ -651,11 +658,15 @@ void QgsSymbolLegendNode::exportSymbolToJson( const QgsLegendSettings &settings,
return;
}


QgsRenderContext ctx;
// QGIS 4.0 - use render context directly here, and note in the dox that the context must be correctly setup
Q_NOWARN_DEPRECATED_PUSH
ctx.setScaleFactor( settings.dpi() / 25.4 );
ctx.setRendererScale( settings.mapScale() );
ctx.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * ctx.scaleFactor() ) ) );
ctx.setForceVectorOutput( true );
Q_NOWARN_DEPRECATED_POP

// ensure that a minimal expression context is available
QgsExpressionContext expContext = context.expressionContext();
Expand Down Expand Up @@ -1166,20 +1177,37 @@ QVariant QgsDataDefinedSizeLegendNode::data( int role ) const

QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( const QgsLegendSettings &settings, QgsLayerTreeModelLegendNode::ItemContext *ctx )
{
// setup temporary render context
QgsRenderContext context;
context.setScaleFactor( settings.dpi() / 25.4 );
context.setRendererScale( settings.mapScale() );
context.setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * context.scaleFactor() ) ) );
context.setForceVectorOutput( true );
// setup temporary render context if none specified
QgsRenderContext *context = nullptr;
std::unique_ptr< QgsRenderContext > tempRenderContext;
if ( ctx && ctx->context )
context = ctx->context;
else
{
tempRenderContext = qgis::make_unique< QgsRenderContext >();
// QGIS 4.0 - make ItemContext compulsory, so we don't have to construct temporary render contexts here
Q_NOWARN_DEPRECATED_PUSH
tempRenderContext->setScaleFactor( settings.dpi() / 25.4 );
tempRenderContext->setRendererScale( settings.mapScale() );
tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
tempRenderContext->setMapToPixel( QgsMapToPixel( 1 / ( settings.mmPerMapUnit() * tempRenderContext->scaleFactor() ) ) );
tempRenderContext->setForceVectorOutput( true );
tempRenderContext->setPainter( ctx ? ctx->painter : nullptr );
tempRenderContext->setFlag( QgsRenderContext::Antialiasing, true );
Q_NOWARN_DEPRECATED_POP

if ( ctx && ctx->painter )
// setup a minimal expression context
QgsExpressionContext expContext;
expContext.appendScopes( QgsExpressionContextUtils::globalProjectLayerScopes( nullptr ) );
tempRenderContext->setExpressionContext( expContext );
context = tempRenderContext.get();
}

if ( context->painter() )
{
context.setPainter( ctx->painter );
ctx->painter->save();
ctx->painter->setRenderHint( QPainter::Antialiasing );
ctx->painter->translate( ctx->columnLeft, ctx->top );
ctx->painter->scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
context->painter()->save();
context->painter()->translate( ctx->columnLeft, ctx->top );
context->painter()->scale( 1 / context->scaleFactor(), 1 / context->scaleFactor() );
}

QgsDataDefinedSizeLegend ddsLegend( *mSettings );
Expand All @@ -1188,14 +1216,14 @@ QgsLayerTreeModelLegendNode::ItemMetrics QgsDataDefinedSizeLegendNode::draw( con

QSizeF contentSize;
double labelXOffset;
ddsLegend.drawCollapsedLegend( context, &contentSize, &labelXOffset );
ddsLegend.drawCollapsedLegend( *context, &contentSize, &labelXOffset );

if ( ctx && ctx->painter )
ctx->painter->restore();
if ( context->painter() )
context->painter()->restore();

ItemMetrics im;
im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
im.labelSize = QSizeF( labelXOffset / context.scaleFactor(), contentSize.height() / context.scaleFactor() );
im.symbolSize = QSizeF( ( contentSize.width() - labelXOffset ) / context->scaleFactor(), contentSize.height() / context->scaleFactor() );
im.labelSize = QSizeF( labelXOffset / context->scaleFactor(), contentSize.height() / context->scaleFactor() );
return im;
}

Expand Down
19 changes: 16 additions & 3 deletions src/core/layout/qgslayoutitemlegend.cpp
Expand Up @@ -97,19 +97,29 @@ void QgsLayoutItemLegend::paint( QPainter *painter, const QStyleOptionGraphicsIt

if ( mLayout )
{
Q_NOWARN_DEPRECATED_PUSH
// no longer required, but left set for api stability
mSettings.setUseAdvancedEffects( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagUseAdvancedEffects );
mSettings.setDpi( dpi );
Q_NOWARN_DEPRECATED_POP
}
if ( mMap && mLayout )
{
Q_NOWARN_DEPRECATED_PUSH
// no longer required, but left set for api stability
mSettings.setMmPerMapUnit( mLayout->convertFromLayoutUnits( mMap->mapUnitsToLayoutUnits(), QgsUnitTypes::LayoutMillimeters ).length() );
Q_NOWARN_DEPRECATED_POP

// use a temporary QgsMapSettings to find out real map scale
QSizeF mapSizePixels = QSizeF( mMap->rect().width() * dotsPerMM, mMap->rect().height() * dotsPerMM );
QgsRectangle mapExtent = mMap->extent();

QgsMapSettings ms = mMap->mapSettings( mapExtent, mapSizePixels, dpi, false );

// no longer required, but left set for api stability
Q_NOWARN_DEPRECATED_PUSH
mSettings.setMapScale( ms.scale() );
Q_NOWARN_DEPRECATED_POP
}
mInitialMapScaleCalculated = true;

Expand Down Expand Up @@ -179,7 +189,12 @@ void QgsLayoutItemLegend::draw( QgsLayoutItemRenderContext &context )
}

if ( mLayout )
{
// no longer required, but left for API compatibility
Q_NOWARN_DEPRECATED_PUSH
mSettings.setDpi( mLayout->renderContext().dpi() );
Q_NOWARN_DEPRECATED_POP
}

QgsLegendRenderer legendRenderer( mLegendModel.get(), mSettings );
legendRenderer.setLegendSize( rect().size() );
Expand Down Expand Up @@ -577,7 +592,7 @@ bool QgsLayoutItemLegend::readPropertiesFromElement( const QDomElement &itemElem
{
QDomElement styleElem = stylesNode.childNodes().at( i ).toElement();
QgsLegendStyle style;
style.readXml( styleElem, doc );
style.readXml( styleElem, doc, context );
QString name = styleElem.attribute( QStringLiteral( "name" ) );
QgsLegendStyle::Style s;
if ( name == QLatin1String( "title" ) ) s = QgsLegendStyle::Title;
Expand Down Expand Up @@ -1041,8 +1056,6 @@ QVariant QgsLegendModel::data( const QModelIndex &index, int role ) const

if ( mLayoutLegend )
expressionContext = mLayoutLegend->createExpressionContext();
else
expressionContext = QgsExpressionContext();

const QList<QgsLayerTreeModelLegendNode *> legendnodes = layerLegendNodes( nodeLayer, false );
if ( legendnodes.count() > 1 ) // evaluate all existing legend nodes but leave the name for the legend evaluator
Expand Down

0 comments on commit 38dfcdf

Please sign in to comment.