[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
This commit is contained in:
Nyall Dawson 2016-07-12 17:18:34 +10:00
parent 93f2eec711
commit 4f31ab656e
5 changed files with 66 additions and 13 deletions

View File

@ -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 )

View File

@ -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

View File

@ -22,7 +22,8 @@ from qgis.core import (QgsComposerLegend,
QgsVectorLayer,
QgsMapLayerRegistry,
QgsMarkerSymbolV2,
QgsSingleSymbolRendererV2
QgsSingleSymbolRendererV2,
QgsRectangle
)
from qgis.testing import (start_app,
unittest
@ -37,22 +38,19 @@ TEST_DATA_DIR = unitTestDataPath()
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)
@ -60,7 +58,7 @@ class TestQgsComposerLegend(unittest.TestCase):
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 @@ class TestQgsComposerLegend(unittest.TestCase):
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.

After

Width:  |  Height:  |  Size: 9.1 KiB