Skip to content
Permalink
Browse files

[composer] Fix setting legend content by map not resizing legend

When a legend was set to filter content by map, it wasn't
consistently being resized to fit the legend contents. This caused
issues for atlas exports where legends could grow but never
shrink.

Fix #14707

On behalf of Faunalia, sponsored by ENEL

(cherry-picked from 4f31ab6)
  • Loading branch information
nyalldawson committed Jul 19, 2016
1 parent 15d875e commit b9193426712a0fee35b152c362c780f0b1f52c1c
@@ -43,6 +43,7 @@ QgsComposerLegend::QgsComposerLegend( QgsComposition* composition )
, mFilterAskedForUpdate( false )
, mInAtlas( false )
, mInitialMapScaleCalculated( false )
, mForceResize( false )
{
mLegendModel2 = new QgsLegendModelV2( QgsProject::instance()->layerTreeRoot() );

@@ -66,6 +67,8 @@ QgsComposerLegend::QgsComposerLegend()
, mFilterOutAtlas( false )
, mFilterAskedForUpdate( false )
, mInAtlas( false )
, mInitialMapScaleCalculated( false )
, mForceResize( false )
{

}
@@ -117,11 +120,18 @@ void QgsComposerLegend::paint( QPainter* painter, const QStyleOptionGraphicsItem
mInitialMapScaleCalculated = true;

QgsLegendRenderer legendRenderer( mLegendModel2, mSettings );
legendRenderer.setLegendSize( rect().size() );
legendRenderer.setLegendSize( mForceResize ? QSize() : rect().size() );

//adjust box if width or height is too small
QSizeF size = legendRenderer.minimumSize();
if ( size.height() > rect().height() || size.width() > rect().width() )
if ( mForceResize )
{
mForceResize = false;
//set new rect, respecting position mode and data defined size/position
QRectF targetRect = QRectF( pos().x(), pos().y(), size.width(), size.height() );
setSceneRect( evalItemRect( targetRect, true ) );
}
else if ( size.height() > rect().height() || size.width() > rect().width() )
{
//need to resize box
QRectF targetRect = QRectF( pos().x(), pos().y(), rect().width(), rect().height() );
@@ -673,6 +683,8 @@ void QgsComposerLegend::doUpdateFilterByMap()
}
else
mLegendModel2->setLegendFilterByMap( nullptr );

mForceResize = true;
}

void QgsComposerLegend::setLegendFilterOutAtlas( bool doFilter )
@@ -296,6 +296,9 @@ class CORE_EXPORT QgsComposerLegend : public QgsComposerItem

//! Will be false until the associated map scale and DPI have been calculated
bool mInitialMapScaleCalculated;

//! Will be true if the legend size should be totally reset at next paint
bool mForceResize;
};

#endif
@@ -22,7 +22,8 @@
QgsVectorLayer,
QgsMapLayerRegistry,
QgsMarkerSymbolV2,
QgsSingleSymbolRendererV2
QgsSingleSymbolRendererV2,
QgsRectangle
)
from qgis.testing import (start_app,
unittest
@@ -37,30 +38,27 @@

class TestQgsComposerLegend(unittest.TestCase):

def __init__(self, methodName):
"""Run once on class initialization."""
unittest.TestCase.__init__(self, methodName)
point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
self.point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
QgsMapLayerRegistry.instance().addMapLayers([self.point_layer])

def testInitialSizeSymbolMapUnits(self):
"""Test initial size of legend with a symbol size in map units"""

point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
QgsMapLayerRegistry.instance().addMapLayers([point_layer])

marker_symbol = QgsMarkerSymbolV2.createSimple({'color': '#ff0000', 'outline_style': 'no', 'size': '5', 'size_unit': 'MapUnit'})

self.point_layer.setRendererV2(QgsSingleSymbolRendererV2(marker_symbol))
point_layer.setRendererV2(QgsSingleSymbolRendererV2(marker_symbol))

s = QgsMapSettings()
s.setLayers([self.point_layer.id()])
s.setLayers([point_layer.id()])
s.setCrsTransformEnabled(False)
composition = QgsComposition(s)
composition.setPaperSize(297, 210)

composer_map = QgsComposerMap(composition, 20, 20, 80, 80)
composer_map.setFrameEnabled(True)
composition.addComposerMap(composer_map)
composer_map.setNewExtent(self.point_layer.extent())
composer_map.setNewExtent(point_layer.extent())

legend = QgsComposerLegend(composition)
legend.setSceneRect(QRectF(120, 20, 80, 80))
@@ -77,6 +75,46 @@ def testInitialSizeSymbolMapUnits(self):
result, message = checker.testComposition()
self.assertTrue(result, message)

QgsMapLayerRegistry.instance().removeMapLayers([point_layer])

def testResizeWithMapContent(self):
"""Test test legend resizes to match map content"""

point_path = os.path.join(TEST_DATA_DIR, 'points.shp')
point_layer = QgsVectorLayer(point_path, 'points', 'ogr')
QgsMapLayerRegistry.instance().addMapLayers([point_layer])

s = QgsMapSettings()
s.setLayers([point_layer.id()])
s.setCrsTransformEnabled(False)
composition = QgsComposition(s)
composition.setPaperSize(297, 210)

composer_map = QgsComposerMap(composition, 20, 20, 80, 80)
composer_map.setFrameEnabled(True)
composition.addComposerMap(composer_map)
composer_map.setNewExtent(point_layer.extent())

legend = QgsComposerLegend(composition)
legend.setSceneRect(QRectF(120, 20, 80, 80))
legend.setFrameEnabled(True)
legend.setFrameOutlineWidth(2)
legend.setBackgroundColor(QColor(200, 200, 200))
legend.setTitle('')
legend.setLegendFilterByMapEnabled(True)
composition.addComposerLegend(legend)
legend.setComposerMap(composer_map)

composer_map.setNewExtent(QgsRectangle(-102.51, 41.16, -102.36, 41.30))

checker = QgsCompositionChecker(
'composer_legend_size_content', composition)
checker.setControlPathPrefix("composer_legend")
result, message = checker.testComposition()
self.assertTrue(result, message)

QgsMapLayerRegistry.instance().removeMapLayers([point_layer])


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

0 comments on commit b919342

Please sign in to comment.
You can’t perform that action at this time.