Skip to content
Permalink
Browse files

[layouts] Add inbuilt validity check to warn when scale bars are

not linked to a map item

(and remove test Web mercator projection warning check)
  • Loading branch information
nyalldawson committed Jan 2, 2019
1 parent ddd522b commit d14a5bd1ddf65dafa085b0beef846db2dcf5e6f0
@@ -16,19 +16,25 @@

#include "qgslayoutvaliditychecks.h"
#include "qgsvaliditycheckcontext.h"
#include "qgslayoutitemmap.h"
#include "qgslayoutitemscalebar.h"
#include "qgslayout.h"

QgsLayoutMapCrsValidityCheck *QgsLayoutMapCrsValidityCheck::create() const
QgsLayoutScaleBarValidityCheck *QgsLayoutScaleBarValidityCheck::create() const
{
return new QgsLayoutMapCrsValidityCheck();
return new QgsLayoutScaleBarValidityCheck();
}

QString QgsLayoutMapCrsValidityCheck::id() const { return QStringLiteral( "map_crs_check" ); }
QString QgsLayoutScaleBarValidityCheck::id() const
{
return QStringLiteral( "layout_scalebar_check" );
}

int QgsLayoutMapCrsValidityCheck::checkType() const { return QgsAbstractValidityCheck::TypeLayoutCheck; }
int QgsLayoutScaleBarValidityCheck::checkType() const
{
return QgsAbstractValidityCheck::TypeLayoutCheck;
}

bool QgsLayoutMapCrsValidityCheck::prepareCheck( const QgsValidityCheckContext *context, QgsFeedback * )
bool QgsLayoutScaleBarValidityCheck::prepareCheck( const QgsValidityCheckContext *context, QgsFeedback * )
{
if ( context->type() != QgsValidityCheckContext::TypeLayoutContext )
return false;
@@ -37,24 +43,25 @@ bool QgsLayoutMapCrsValidityCheck::prepareCheck( const QgsValidityCheckContext *
if ( !layoutContext )
return false;

QList< QgsLayoutItemMap * > mapItems;
layoutContext->layout->layoutItems( mapItems );
for ( QgsLayoutItemMap *map : qgis::as_const( mapItems ) )
QList< QgsLayoutItemScaleBar * > barItems;
layoutContext->layout->layoutItems( barItems );
for ( QgsLayoutItemScaleBar *bar : qgis::as_const( barItems ) )
{
if ( map->crs().authid() == QStringLiteral( "EPSG:3857" ) )
if ( !bar->linkedMap() )
{
QgsValidityCheckResult res;
res.type = QgsValidityCheckResult::Warning;
res.title = tr( "Map projection is misleading" );
res.detailedDescription = tr( "The projection for the map item %1 is set to <i>Web Mercator (EPSG:3857)</i> which misrepresents areas and shapes. Consider using an appropriate local projection instead." ).arg( map->displayName() );
res.title = tr( "Scalebar is not linked to a map" );
const QString name = bar->displayName().toHtmlEscaped();
res.detailedDescription = tr( "The scalebar “%1” is not linked to a map item. This scale will be misleading." ).arg( name );
mResults.append( res );
}
}

return true;
}

QList<QgsValidityCheckResult> QgsLayoutMapCrsValidityCheck::runCheck( const QgsValidityCheckContext *, QgsFeedback * )
QList<QgsValidityCheckResult> QgsLayoutScaleBarValidityCheck::runCheck( const QgsValidityCheckContext *, QgsFeedback * )
{
return mResults;
}
@@ -15,14 +15,13 @@
***************************************************************************/

#include "qgsabstractvaliditycheck.h"
#include "qgis_app.h"

class QgsLayoutMapCrsValidityCheck : public QgsAbstractValidityCheck
class APP_EXPORT QgsLayoutScaleBarValidityCheck : public QgsAbstractValidityCheck
{
Q_OBJECT

public:

QgsLayoutMapCrsValidityCheck *create() const override;
QgsLayoutScaleBarValidityCheck *create() const override;
QString id() const override;
int checkType() const override;
bool prepareCheck( const QgsValidityCheckContext *context, QgsFeedback *feedback ) override;
@@ -1233,7 +1233,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
setIconSizes( size );
}

QgsApplication::validityCheckRegistry()->addCheck( new QgsLayoutMapCrsValidityCheck() );
QgsApplication::validityCheckRegistry()->addCheck( new QgsLayoutScaleBarValidityCheck() );

mSplash->showMessage( tr( "Initializing file filters" ), Qt::AlignHCenter | Qt::AlignBottom );
qApp->processEvents();
@@ -12,6 +12,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/src/core/metadata
${CMAKE_SOURCE_DIR}/src/core/raster
${CMAKE_SOURCE_DIR}/src/core/symbology
${CMAKE_SOURCE_DIR}/src/core/validity
${CMAKE_SOURCE_DIR}/src/ui
${CMAKE_SOURCE_DIR}/src/gui
${CMAKE_SOURCE_DIR}/src/gui/editorwidgets
@@ -113,4 +114,4 @@ ADD_QGIS_TEST(vectorlayersaveasdialogtest testqgsvectorlayersaveasdialog.cpp)
ADD_QGIS_TEST(maptoolreverselinetest testqgsmaptoolreverseline.cpp)
ADD_QGIS_TEST(maptooltrimextendfeaturetest testqgsmaptooltrimextendfeature.cpp)
ADD_QGIS_TEST(projectproperties testqgsprojectproperties.cpp)

ADD_QGIS_TEST(layoutvaliditychecks testqgsapplayoutvaliditychecks.cpp)
@@ -0,0 +1,106 @@
/***************************************************************************
testqgsapplayoutvaliditychecks.cpp
--------------------------------------
Date : January 2019
Copyright : (C) 2019 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 "qgstest.h"

#include <QObject>
#include <QString>
#include <QStringList>

//qgis includes...
#include "qgsdataitem.h"
#include "qgsapplication.h"
#include "qgslogger.h"
#include "qgsproject.h"
#include "qgslayout.h"
#include "qgslayoutitemscalebar.h"
#include "qgslayoutitemmap.h"
#include "qgsabstractvaliditycheck.h"
#include "qgsvaliditycheckcontext.h"
#include "layout/qgslayoutvaliditychecks.h"
#include "qgsfeedback.h"

class TestQgsLayoutValidityChecks : public QObject
{
Q_OBJECT

public:
TestQgsLayoutValidityChecks();

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.

void testScaleBarValidity();

private:
QString mTestDataDir;
};

TestQgsLayoutValidityChecks::TestQgsLayoutValidityChecks() = default;

void TestQgsLayoutValidityChecks::initTestCase()
{
//
// Runs once before any tests are run
//
// init QGIS's paths - true means that all path will be inited from prefix
QgsApplication::init();
QgsApplication::initQgis();
QgsApplication::showSettings();

QString dataDir( TEST_DATA_DIR ); //defined in CmakeLists.txt
mTestDataDir = dataDir + '/';
}

void TestQgsLayoutValidityChecks::cleanupTestCase()
{
QgsApplication::exitQgis();
}

void TestQgsLayoutValidityChecks::testScaleBarValidity()
{
QgsProject p;
QgsLayout l( &p );

QgsLayoutItemScaleBar *scale = new QgsLayoutItemScaleBar( &l );
l.addItem( scale );

QgsLayoutValidityCheckContext context( &l );
QgsFeedback f;

// scalebar not linked to map
QgsLayoutScaleBarValidityCheck check;
QVERIFY( check.prepareCheck( &context, &f ) );
QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
QCOMPARE( res.size(), 1 );
QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );

// now link a map
QgsLayoutItemMap *map = new QgsLayoutItemMap( &l );
l.addItem( map );
scale->setLinkedMap( map );

QgsLayoutScaleBarValidityCheck check2;
QVERIFY( check2.prepareCheck( &context, &f ) );
res = check2.runCheck( &context, &f );
QCOMPARE( res.size(), 0 );
}



QGSTEST_MAIN( TestQgsLayoutValidityChecks )
#include "testqgsapplayoutvaliditychecks.moc"

0 comments on commit d14a5bd

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