API Improvements to handling layered layout exports, add tests

Fixes #20253
This commit is contained in:
Nyall Dawson 2019-08-09 14:14:38 +10:00
parent 568aabb6dd
commit 3fe851a306
7 changed files with 330 additions and 31 deletions

View File

@ -394,6 +394,13 @@ Returns 0 if this item is to be placed on the same layer as the previous item,
Items which require multiply layers should check QgsLayoutContext.currentExportLayer() during
their rendering to determine which layer should be drawn.
%End
virtual QString exportLayerName( int layer ) const;
%Docstring
Returns a user-friendly name for the specified export ``layer``.
.. versionadded:: 3.10
%End
virtual void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget );

View File

@ -89,6 +89,8 @@ The caller takes responsibility for deleting the returned object.
virtual int numberExportLayers() const;
virtual QString exportLayerName( int layer ) const;
virtual void setFrameStrokeWidth( QgsLayoutMeasurement width );

View File

@ -244,6 +244,11 @@ void QgsLayoutItem::setParentGroup( QgsLayoutItemGroup *group )
setFlag( QGraphicsItem::ItemIsSelectable, !static_cast< bool>( group ) ); //item in groups cannot be selected
}
QString QgsLayoutItem::exportLayerName( int ) const
{
return QString();
}
void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
{
if ( !painter || !painter->device() || !shouldDrawItem() )

View File

@ -424,6 +424,13 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
*/
virtual int numberExportLayers() const { return 0; }
/**
* Returns a user-friendly name for the specified export \a layer.
*
* \since QGIS 3.10
*/
virtual QString exportLayerName( int layer ) const;
/**
* Handles preparing a paint surface for the layout item and painting the item's
* content. Derived classes must not override this method, but instead implement

View File

@ -988,11 +988,45 @@ int QgsLayoutItemMap::numberExportLayers() const
{
return ( hasBackground() ? 1 : 0 )
+ layersToRender().length()
+ 1 // for grids, if they exist
+ 1 // for overviews, if they exist
+ ( mGridStack->hasEnabledItems() ? 1 : 0 )
+ ( mOverviewStack->hasEnabledItems() ? 1 : 0 )
+ ( frameEnabled() ? 1 : 0 );
}
QString QgsLayoutItemMap::exportLayerName( int layer ) const
{
if ( hasBackground() && layer == 0 )
return tr( "Map Background" );
else if ( hasBackground() )
layer--;
const QList< QgsMapLayer * > layers = layersToRender();
const int layerCount = layers.length();
if ( layer < layerCount )
{
// layers are in reverse order
return layers.at( layerCount - layer - 1 )->name();
}
layer -= layerCount;
const bool hasGrids = mGridStack->hasEnabledItems();
if ( hasGrids && layer == 0 )
return tr( "Map Grids" );
else if ( hasGrids )
layer--;
const bool hasOverviews = mOverviewStack->hasEnabledItems();
if ( hasOverviews && layer == 0 )
return tr( "Map Overviews" );
else if ( hasOverviews )
layer--;
if ( frameEnabled() && layer == 0 )
return tr( "Map Frame" );
return QString();
}
void QgsLayoutItemMap::setFrameStrokeWidth( const QgsLayoutMeasurement width )
{
QgsLayoutItem::setFrameStrokeWidth( width );
@ -1939,43 +1973,63 @@ bool QgsLayoutItemMap::shouldDrawPart( QgsLayoutItemMap::PartType part ) const
return true;
}
int idx = numberExportLayers();
if ( isSelected() )
if ( hasBackground() )
{
--idx;
if ( SelectionBoxes == part )
if ( part == Background )
return currentExportLayer == 0;
currentExportLayer--;
}
else if ( part == Background )
return false;
// layers
const int layerCount = layersToRender().length();
if ( currentExportLayer >= 0 && currentExportLayer < layerCount )
{
return currentExportLayer == idx;
return part == Layer;
}
else if ( part == Layer )
return false;
currentExportLayer -= layerCount;
if ( mGridStack->hasEnabledItems() )
{
if ( part == Grid )
return currentExportLayer == 0;
currentExportLayer--;
}
else if ( part == Grid )
return false;
if ( mOverviewStack->hasEnabledItems() )
{
if ( part == OverviewMapExtent )
return currentExportLayer == 0;
currentExportLayer--;
}
else if ( part == OverviewMapExtent )
return false;
if ( frameEnabled() )
{
--idx;
if ( Frame == part )
{
return currentExportLayer == idx;
}
}
--idx;
if ( OverviewMapExtent == part )
{
return currentExportLayer == idx;
}
--idx;
if ( Grid == part )
{
return currentExportLayer == idx;
}
if ( hasBackground() )
{
if ( Background == part )
{
if ( part == Frame )
return currentExportLayer == 0;
currentExportLayer--;
}
else if ( part == Frame )
return false;
if ( SelectionBoxes == part )
{
return isSelected();
}
return true; // for Layer
return false;
}
void QgsLayoutItemMap::refreshMapExtents( const QgsExpressionContext *context )

View File

@ -117,6 +117,7 @@ class CORE_EXPORT QgsLayoutItemMap : public QgsLayoutItem
// for now, map items behave a bit differently and don't implement draw. TODO - see if we can avoid this
void paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget *pWidget ) override;
int numberExportLayers() const override;
QString exportLayerName( int layer ) const override;
void setFrameStrokeWidth( QgsLayoutMeasurement width ) override;
/**

View File

@ -63,6 +63,7 @@ class TestQgsLayoutMap : public QObject
void labelBlockingRegions();
void testSimplificationMethod();
void testRenderedFeatureHandler();
void testLayeredExport();
private:
QgsRasterLayer *mRasterLayer = nullptr;
@ -871,5 +872,227 @@ void TestQgsLayoutMap::testRenderedFeatureHandler()
QVERIFY( features1.isEmpty() );
}
void TestQgsLayoutMap::testLayeredExport()
{
QgsVectorLayer *linesLayer = new QgsVectorLayer( TEST_DATA_DIR + QStringLiteral( "/lines.shp" ),
QStringLiteral( "lines" ), QStringLiteral( "ogr" ) );
QVERIFY( linesLayer->isValid() );
QgsVectorLayer *pointsLayer = new QgsVectorLayer( TEST_DATA_DIR + QStringLiteral( "/points.shp" ),
QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
QVERIFY( pointsLayer->isValid() );
QgsProject p;
p.addMapLayer( linesLayer );
p.addMapLayer( pointsLayer );
QgsLayout l( &p );
l.initializeDefaults();
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
map->attemptSetSceneRect( QRectF( 20, 20, 200, 100 ) );
map->setFrameEnabled( false );
map->setBackgroundEnabled( false );
map->setCrs( linesLayer->crs() );
map->zoomToExtent( linesLayer->extent() );
map->setLayers( QList<QgsMapLayer *>() << linesLayer );
l.addLayoutItem( map );
QCOMPARE( map->numberExportLayers(), 1 );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
map->setFrameEnabled( true );
QCOMPARE( map->numberExportLayers(), 2 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
map->setBackgroundEnabled( true );
QCOMPARE( map->numberExportLayers(), 3 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "Map Background" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 2 );
QCOMPARE( map->exportLayerName( 2 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
map->setBackgroundEnabled( false );
map->grid()->setEnabled( true );
QCOMPARE( map->numberExportLayers(), 3 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "Map Grids" ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 2 );
QCOMPARE( map->exportLayerName( 2 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
map->setBackgroundEnabled( false );
map->overview()->setEnabled( true );
QCOMPARE( map->numberExportLayers(), 4 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "Map Grids" ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 2 );
QCOMPARE( map->exportLayerName( 2 ), QStringLiteral( "Map Overviews" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 3 );
QCOMPARE( map->exportLayerName( 3 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
// add second layer
map->setLayers( QList<QgsMapLayer *>() << linesLayer << pointsLayer );
QCOMPARE( map->numberExportLayers(), 5 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "points" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 2 );
QCOMPARE( map->exportLayerName( 2 ), QStringLiteral( "Map Grids" ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 3 );
QCOMPARE( map->exportLayerName( 3 ), QStringLiteral( "Map Overviews" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 4 );
QCOMPARE( map->exportLayerName( 4 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
map->setBackgroundEnabled( true );
QCOMPARE( map->numberExportLayers(), 6 );
l.renderContext().setCurrentExportLayer( 0 );
QCOMPARE( map->exportLayerName( 0 ), QStringLiteral( "Map Background" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 1 );
QCOMPARE( map->exportLayerName( 1 ), QStringLiteral( "points" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 2 );
QCOMPARE( map->exportLayerName( 2 ), QStringLiteral( "lines" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 3 );
QCOMPARE( map->exportLayerName( 3 ), QStringLiteral( "Map Grids" ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 4 );
QCOMPARE( map->exportLayerName( 4 ), QStringLiteral( "Map Overviews" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
l.renderContext().setCurrentExportLayer( 5 );
QCOMPARE( map->exportLayerName( 5 ), QStringLiteral( "Map Frame" ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Grid ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::OverviewMapExtent ) );
QVERIFY( map->shouldDrawPart( QgsLayoutItemMap::Frame ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Background ) );
QVERIFY( !map->shouldDrawPart( QgsLayoutItemMap::Layer ) );
}
QGSTEST_MAIN( TestQgsLayoutMap )
#include "testqgslayoutmap.moc"