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 c081ceb commit a960c02c6d22f37010b950fa9bb0a45e77ee4cb0
@@ -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() );
@@ -674,6 +684,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 a960c02

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