Restore more atlas tests
@ -1917,6 +1917,7 @@ void QgsLayoutItemMap::updateAtlasFeature()
|
||||
|
||||
// set the new extent (and render)
|
||||
setExtent( newExtent );
|
||||
emit preparedForAtlas();
|
||||
}
|
||||
|
||||
QgsRectangle QgsLayoutItemMap::computeAtlasRectangle()
|
||||
|
@ -134,6 +134,7 @@ SET(TESTS
|
||||
testqgslabelingengine.cpp
|
||||
testqgslayertree.cpp
|
||||
testqgslayout.cpp
|
||||
testqgslayoutatlas.cpp
|
||||
testqgslayoutcontext.cpp
|
||||
testqgslayouthtml.cpp
|
||||
testqgslayoutitem.cpp
|
||||
|
428
tests/src/core/testqgslayoutatlas.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
/***************************************************************************
|
||||
testqgslayoutatlas.cpp
|
||||
---------------------------
|
||||
begin : December 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslayout.h"
|
||||
#include "qgsmultirenderchecker.h"
|
||||
#include "qgslayoutitemmap.h"
|
||||
#include "qgslayoutitemmapoverview.h"
|
||||
#include "qgslayoutatlas.h"
|
||||
#include "qgslayoutitemlabel.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgssymbol.h"
|
||||
#include "qgssinglesymbolrenderer.h"
|
||||
#include "qgsfontutils.h"
|
||||
#include "qgsprintlayout.h"
|
||||
#include <QObject>
|
||||
#include <QtTest/QSignalSpy>
|
||||
#include "qgstest.h"
|
||||
|
||||
class TestQgsLayoutAtlas : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TestQgsLayoutAtlas() = default;
|
||||
|
||||
private slots:
|
||||
void initTestCase();// will be called before the first testfunction is executed.
|
||||
void cleanupTestCase();// will be called after the last testfunction was executed.
|
||||
void init();// will be called before each testfunction is executed.
|
||||
void cleanup();// will be called after every testfunction.
|
||||
|
||||
// test filename pattern evaluation
|
||||
void filename();
|
||||
// test rendering with an autoscale atlas
|
||||
void autoscale_render();
|
||||
// test rendering with a fixed scale atlas
|
||||
void fixedscale_render();
|
||||
// test rendering with predefined scales
|
||||
void predefinedscales_render();
|
||||
// test rendering with two atlas-driven maps
|
||||
void two_map_autoscale_render();
|
||||
// test rendering with a hidden coverage
|
||||
void hiding_render();
|
||||
// test rendering with feature sorting
|
||||
void sorting_render();
|
||||
// test rendering with feature filtering
|
||||
void filtering_render();
|
||||
// test render signals
|
||||
void test_signals();
|
||||
// test removing coverage layer while atlas is enabled
|
||||
void test_remove_layer();
|
||||
|
||||
private:
|
||||
QgsPrintLayout *mLayout = nullptr;
|
||||
QgsLayoutItemLabel *mLabel1 = nullptr;
|
||||
QgsLayoutItemLabel *mLabel2 = nullptr;
|
||||
QgsLayoutItemMap *mAtlasMap = nullptr;
|
||||
QgsLayoutItemMap *mOverview = nullptr;
|
||||
QgsVectorLayer *mVectorLayer = nullptr;
|
||||
QgsVectorLayer *mVectorLayer2 = nullptr;
|
||||
QgsLayoutAtlas *mAtlas = nullptr;
|
||||
QString mReport;
|
||||
};
|
||||
|
||||
void TestQgsLayoutAtlas::initTestCase()
|
||||
{
|
||||
QgsApplication::init();
|
||||
QgsApplication::initQgis();
|
||||
|
||||
//create maplayers from testdata and add to layer registry
|
||||
QFileInfo vectorFileInfo( QStringLiteral( TEST_DATA_DIR ) + "/france_parts.shp" );
|
||||
mVectorLayer = new QgsVectorLayer( vectorFileInfo.filePath(),
|
||||
vectorFileInfo.completeBaseName(),
|
||||
QStringLiteral( "ogr" ) );
|
||||
mVectorLayer2 = new QgsVectorLayer( vectorFileInfo.filePath(),
|
||||
vectorFileInfo.completeBaseName(),
|
||||
QStringLiteral( "ogr" ) );
|
||||
|
||||
QgsVectorSimplifyMethod simplifyMethod;
|
||||
simplifyMethod.setSimplifyHints( QgsVectorSimplifyMethod::NoSimplification );
|
||||
mVectorLayer->setSimplifyMethod( simplifyMethod );
|
||||
|
||||
mReport = QStringLiteral( "<h1>Composer Atlas Tests</h1>\n" );
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::cleanupTestCase()
|
||||
{
|
||||
delete mLayout;
|
||||
delete mVectorLayer;
|
||||
QgsApplication::exitQgis();
|
||||
|
||||
QString myReportFile = QDir::tempPath() + "/qgistest.html";
|
||||
QFile myFile( myReportFile );
|
||||
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
|
||||
{
|
||||
QTextStream myQTextStream( &myFile );
|
||||
myQTextStream << mReport;
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::init()
|
||||
{
|
||||
//create composition with composer map
|
||||
|
||||
// select epsg:2154
|
||||
QgsCoordinateReferenceSystem crs;
|
||||
crs.createFromSrid( 2154 );
|
||||
QgsProject::instance()->setCrs( crs );
|
||||
mLayout = new QgsPrintLayout( QgsProject::instance() );
|
||||
mLayout->initializeDefaults();
|
||||
|
||||
// fix the renderer, fill with green
|
||||
QgsStringMap props;
|
||||
props.insert( QStringLiteral( "color" ), QStringLiteral( "0,127,0" ) );
|
||||
QgsFillSymbol *fillSymbol = QgsFillSymbol::createSimple( props );
|
||||
QgsSingleSymbolRenderer *renderer = new QgsSingleSymbolRenderer( fillSymbol );
|
||||
mVectorLayer->setRenderer( renderer );
|
||||
|
||||
// the atlas map
|
||||
mAtlasMap = new QgsLayoutItemMap( mLayout );
|
||||
mAtlasMap->attemptSetSceneRect( QRectF( 20, 20, 130, 130 ) );
|
||||
mAtlasMap->setFrameEnabled( true );
|
||||
mLayout->addLayoutItem( mAtlasMap );
|
||||
mAtlasMap->setLayers( QList<QgsMapLayer *>() << mVectorLayer );
|
||||
|
||||
mAtlas = mLayout->atlas();
|
||||
mAtlas->setCoverageLayer( mVectorLayer );
|
||||
mAtlas->setEnabled( true );
|
||||
|
||||
// an overview
|
||||
mOverview = new QgsLayoutItemMap( mLayout );
|
||||
mOverview->attemptSetSceneRect( QRectF( 180, 20, 50, 50 ) );
|
||||
mOverview->setFrameEnabled( true );
|
||||
mOverview->overview()->setFrameMap( mAtlasMap );
|
||||
mOverview->setLayers( QList<QgsMapLayer *>() << mVectorLayer );
|
||||
mLayout->addLayoutItem( mOverview );
|
||||
mOverview->setExtent( QgsRectangle( 49670.718, 6415139.086, 699672.519, 7065140.887 ) );
|
||||
|
||||
// set the fill symbol of the overview map
|
||||
QgsStringMap props2;
|
||||
props2.insert( QStringLiteral( "color" ), QStringLiteral( "127,0,0,127" ) );
|
||||
QgsFillSymbol *fillSymbol2 = QgsFillSymbol::createSimple( props2 );
|
||||
mOverview->overview()->setFrameSymbol( fillSymbol2 );
|
||||
|
||||
// header label
|
||||
mLabel1 = new QgsLayoutItemLabel( mLayout );
|
||||
mLayout->addLayoutItem( mLabel1 );
|
||||
mLabel1->setText( QStringLiteral( "[% \"NAME_1\" %] area" ) );
|
||||
mLabel1->setFont( QgsFontUtils::getStandardTestFont() );
|
||||
mLabel1->setMarginX( 1 );
|
||||
mLabel1->setMarginY( 1 );
|
||||
//need to explicitly set width, since expression hasn't been evaluated against
|
||||
//an atlas feature yet and will be shorter than required
|
||||
mLabel1->attemptSetSceneRect( QRectF( 150, 5, 60, 15 ) );
|
||||
|
||||
// feature number label
|
||||
mLabel2 = new QgsLayoutItemLabel( mLayout );
|
||||
mLayout->addLayoutItem( mLabel2 );
|
||||
mLabel2->setText( QStringLiteral( "# [%@atlas_featurenumber || ' / ' || @atlas_totalfeatures%]" ) );
|
||||
mLabel2->setFont( QgsFontUtils::getStandardTestFont() );
|
||||
mLabel2->attemptSetSceneRect( QRectF( 150, 200, 60, 15 ) );
|
||||
mLabel2->setMarginX( 1 );
|
||||
mLabel2->setMarginY( 1 );
|
||||
|
||||
|
||||
qDebug() << "header label font: " << mLabel1->font().toString() << " exactMatch:" << mLabel1->font().exactMatch();
|
||||
qDebug() << "feature number label font: " << mLabel2->font().toString() << " exactMatch:" << mLabel2->font().exactMatch();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::cleanup()
|
||||
{
|
||||
delete mLayout;
|
||||
mLayout = nullptr;
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::filename()
|
||||
{
|
||||
QString error;
|
||||
mAtlas->setFilenameExpression( QStringLiteral( "'output_' || @atlas_featurenumber" ), error );
|
||||
mAtlas->beginRender();
|
||||
for ( int fi = 0; fi < mAtlas->count(); ++fi )
|
||||
{
|
||||
mAtlas->seekTo( fi );
|
||||
QString expected = QStringLiteral( "output_%1" ).arg( ( int )( fi + 1 ) );
|
||||
QCOMPARE( mAtlas->currentFilename(), expected );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
|
||||
void TestQgsLayoutAtlas::autoscale_render()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Auto );
|
||||
mAtlasMap->setAtlasMargin( 0.10 );
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_autoscale%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::fixedscale_render()
|
||||
{
|
||||
//TODO QGIS3.0 - setting the extent AFTER setting atlas driven/fixed scaling mode should
|
||||
//also update the set fixed scale
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_fixedscale%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::predefinedscales_render()
|
||||
{
|
||||
//TODO QGIS3.0 - setting the extent AFTER setting atlas driven/predefined scaling mode should
|
||||
//also update the atlas map scale
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Predefined );
|
||||
|
||||
QVector<qreal> scales;
|
||||
scales << 1800000.0;
|
||||
scales << 5000000.0;
|
||||
mLayout->context().setPredefinedScales( scales );
|
||||
{
|
||||
const QVector<qreal> &setScales = mLayout->context().predefinedScales();
|
||||
for ( int i = 0; i < setScales.size(); i++ )
|
||||
{
|
||||
QVERIFY( setScales[i] == scales[i] );
|
||||
}
|
||||
}
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_predefinedscales%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::two_map_autoscale_render()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 332719.06221504929, 6765214.5887386119, 560957.85090677091, 6993453.3774303338 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Auto );
|
||||
mAtlasMap->setAtlasMargin( 0.10 );
|
||||
mOverview->setAtlasDriven( true );
|
||||
mOverview->setAtlasScalingMode( QgsLayoutItemMap::Auto );
|
||||
mOverview->setAtlasMargin( 2.0 );
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_two_maps%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::hiding_render()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
|
||||
mAtlas->setHideCoverage( true );
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_hiding%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::sorting_render()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
|
||||
mAtlas->setHideCoverage( false );
|
||||
|
||||
mAtlas->setSortFeatures( true );
|
||||
mAtlas->setSortExpression( QStringLiteral( "NAME_1" ) ); // departement name
|
||||
mAtlas->setSortAscending( false );
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_sorting%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::filtering_render()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
|
||||
mAtlas->setHideCoverage( false );
|
||||
|
||||
mAtlas->setSortFeatures( false );
|
||||
|
||||
mAtlas->setFilterFeatures( true );
|
||||
QString error;
|
||||
mAtlas->setFilterExpression( QStringLiteral( "substr(NAME_1,1,1)='P'" ), error ); // select only 'Pays de la Loire'
|
||||
|
||||
mAtlas->beginRender();
|
||||
|
||||
for ( int fit = 0; fit < 1; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
|
||||
QgsLayoutChecker checker( QStringLiteral( "atlas_filtering%1" ).arg( ( ( int )fit ) + 1 ), mLayout );
|
||||
checker.setControlPathPrefix( QStringLiteral( "atlas" ) );
|
||||
QVERIFY( checker.testLayout( mReport, 0, 100 ) );
|
||||
}
|
||||
mAtlas->endRender();
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::test_signals()
|
||||
{
|
||||
mAtlasMap->setExtent( QgsRectangle( 209838.166, 6528781.020, 610491.166, 6920530.620 ) );
|
||||
mAtlasMap->setAtlasDriven( true );
|
||||
mAtlasMap->setAtlasScalingMode( QgsLayoutItemMap::Fixed );
|
||||
mAtlas->setHideCoverage( false );
|
||||
mAtlas->setSortFeatures( false );
|
||||
mAtlas->setFilterFeatures( false );
|
||||
|
||||
QSignalSpy spyRenderBegun( mAtlas, &QgsLayoutAtlas::renderBegun );
|
||||
QSignalSpy spyRenderEnded( mAtlas, &QgsLayoutAtlas::renderEnded );
|
||||
QSignalSpy spyFeatureChanged( mAtlas, &QgsLayoutAtlas::featureChanged );
|
||||
QSignalSpy spyPreparedForAtlas( mAtlasMap, &QgsLayoutItemMap::preparedForAtlas );
|
||||
mAtlas->beginRender();
|
||||
|
||||
QCOMPARE( spyRenderBegun.count(), 1 );
|
||||
|
||||
for ( int fit = 0; fit < 2; ++fit )
|
||||
{
|
||||
mAtlas->seekTo( fit );
|
||||
mLabel1->adjustSizeToText();
|
||||
}
|
||||
QCOMPARE( spyPreparedForAtlas.count(), 2 );
|
||||
QCOMPARE( spyFeatureChanged.count(), 2 );
|
||||
mAtlas->endRender();
|
||||
QCOMPARE( spyRenderEnded.count(), 1 );
|
||||
}
|
||||
|
||||
void TestQgsLayoutAtlas::test_remove_layer()
|
||||
{
|
||||
QgsProject::instance()->addMapLayer( mVectorLayer2 );
|
||||
mAtlas->setCoverageLayer( mVectorLayer2 );
|
||||
mAtlas->setEnabled( true );
|
||||
|
||||
QSignalSpy spyToggled( mAtlas, SIGNAL( toggled( bool ) ) );
|
||||
|
||||
//remove coverage layer while atlas is enabled
|
||||
QgsProject::instance()->removeMapLayer( mVectorLayer2->id() );
|
||||
mVectorLayer2 = nullptr;
|
||||
|
||||
QVERIFY( !mAtlas->enabled() );
|
||||
QVERIFY( spyToggled.count() == 1 );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsLayoutAtlas )
|
||||
#include "testqgslayoutatlas.moc"
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |