mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[layouts] Show an explicit warning when exporting a layout which contains a broken image
This commit is contained in:
parent
4559d9e496
commit
e670371fa3
@ -79,6 +79,8 @@ this value. The path can either be a local path or a remote (http) path.
|
||||
:return: path for the source image
|
||||
|
||||
.. seealso:: :py:func:`setPicturePath`
|
||||
|
||||
.. seealso:: :py:func:`evaluatedPath`
|
||||
%End
|
||||
|
||||
double pictureRotation() const;
|
||||
@ -252,6 +254,24 @@ Returns the current picture mode (image format).
|
||||
virtual void finalizeRestoreFromXml();
|
||||
|
||||
|
||||
bool isMissingImage() const;
|
||||
%Docstring
|
||||
Returns true if the source image is missing and the picture
|
||||
cannot be rendered.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
QString evaluatedPath() const;
|
||||
%Docstring
|
||||
Returns the current evaluated picture path, which includes
|
||||
the result of data defined path overrides.
|
||||
|
||||
.. seealso:: :py:func:`picturePath`
|
||||
|
||||
.. versionadded:: 3.6
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
void setPictureRotation( double rotation );
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "qgsvaliditycheckcontext.h"
|
||||
#include "qgslayoutitemscalebar.h"
|
||||
#include "qgslayoutitemmap.h"
|
||||
#include "qgslayoutitempicture.h"
|
||||
#include "qgslayout.h"
|
||||
|
||||
//
|
||||
@ -126,3 +127,61 @@ QList<QgsValidityCheckResult> QgsLayoutOverviewValidityCheck::runCheck( const Qg
|
||||
{
|
||||
return mResults;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// QgsLayoutPictureSourceValidityCheck
|
||||
//
|
||||
|
||||
QgsLayoutPictureSourceValidityCheck *QgsLayoutPictureSourceValidityCheck::create() const
|
||||
{
|
||||
return new QgsLayoutPictureSourceValidityCheck();
|
||||
}
|
||||
|
||||
QString QgsLayoutPictureSourceValidityCheck::id() const
|
||||
{
|
||||
return QStringLiteral( "layout_picture_source_check" );
|
||||
}
|
||||
|
||||
int QgsLayoutPictureSourceValidityCheck::checkType() const
|
||||
{
|
||||
return QgsAbstractValidityCheck::TypeLayoutCheck;
|
||||
}
|
||||
|
||||
bool QgsLayoutPictureSourceValidityCheck::prepareCheck( const QgsValidityCheckContext *context, QgsFeedback * )
|
||||
{
|
||||
if ( context->type() != QgsValidityCheckContext::TypeLayoutContext )
|
||||
return false;
|
||||
|
||||
const QgsLayoutValidityCheckContext *layoutContext = static_cast< const QgsLayoutValidityCheckContext * >( context );
|
||||
if ( !layoutContext )
|
||||
return false;
|
||||
|
||||
QList< QgsLayoutItemPicture * > pictureItems;
|
||||
layoutContext->layout->layoutItems( pictureItems );
|
||||
for ( QgsLayoutItemPicture *picture : qgis::as_const( pictureItems ) )
|
||||
{
|
||||
if ( picture->isMissingImage() )
|
||||
{
|
||||
QgsValidityCheckResult res;
|
||||
res.type = QgsValidityCheckResult::Warning;
|
||||
res.title = QObject::tr( "Picture source is missing or corrupt" );
|
||||
const QString name = picture->displayName().toHtmlEscaped();
|
||||
|
||||
const QUrl picUrl = QUrl::fromUserInput( picture->evaluatedPath() );
|
||||
const bool isLocalFile = picUrl.isLocalFile();
|
||||
|
||||
res.detailedDescription = QObject::tr( "The source for picture “%1” could not be loaded or is corrupt:<p>%2" ).arg( name,
|
||||
isLocalFile ? QDir::toNativeSeparators( picture->evaluatedPath() ) : picture->evaluatedPath() );
|
||||
mResults.append( res );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<QgsValidityCheckResult> QgsLayoutPictureSourceValidityCheck::runCheck( const QgsValidityCheckContext *, QgsFeedback * )
|
||||
{
|
||||
return mResults;
|
||||
}
|
||||
|
@ -44,3 +44,18 @@ class APP_EXPORT QgsLayoutOverviewValidityCheck : public QgsAbstractValidityChec
|
||||
private:
|
||||
QList<QgsValidityCheckResult> mResults;
|
||||
};
|
||||
|
||||
class APP_EXPORT QgsLayoutPictureSourceValidityCheck : public QgsAbstractValidityCheck
|
||||
{
|
||||
public:
|
||||
|
||||
QgsLayoutPictureSourceValidityCheck *create() const override;
|
||||
QString id() const override;
|
||||
int checkType() const override;
|
||||
bool prepareCheck( const QgsValidityCheckContext *context, QgsFeedback *feedback ) override;
|
||||
QList< QgsValidityCheckResult > runCheck( const QgsValidityCheckContext *context, QgsFeedback *feedback ) override;
|
||||
|
||||
private:
|
||||
QList<QgsValidityCheckResult> mResults;
|
||||
};
|
||||
|
||||
|
@ -1244,6 +1244,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh
|
||||
|
||||
QgsApplication::validityCheckRegistry()->addCheck( new QgsLayoutScaleBarValidityCheck() );
|
||||
QgsApplication::validityCheckRegistry()->addCheck( new QgsLayoutOverviewValidityCheck() );
|
||||
QgsApplication::validityCheckRegistry()->addCheck( new QgsLayoutPictureSourceValidityCheck() );
|
||||
|
||||
mSplash->showMessage( tr( "Initializing file filters" ), Qt::AlignHCenter | Qt::AlignBottom );
|
||||
qApp->processEvents();
|
||||
|
@ -485,6 +485,8 @@ void QgsLayoutItemPicture::updateMapRotation()
|
||||
|
||||
void QgsLayoutItemPicture::loadPicture( const QString &path )
|
||||
{
|
||||
mIsMissingImage = false;
|
||||
mEvaluatedPath = path;
|
||||
if ( path.startsWith( QLatin1String( "http" ) ) )
|
||||
{
|
||||
//remote location
|
||||
@ -503,6 +505,7 @@ void QgsLayoutItemPicture::loadPicture( const QString &path )
|
||||
{
|
||||
//trying to load an invalid file or bad expression, show cross picture
|
||||
mMode = FormatSVG;
|
||||
mIsMissingImage = true;
|
||||
QString badFile( QStringLiteral( ":/images/composer/missing_image.svg" ) );
|
||||
mSVG.load( badFile );
|
||||
if ( mSVG.isValid() )
|
||||
@ -569,6 +572,16 @@ QSizeF QgsLayoutItemPicture::pictureSize()
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsLayoutItemPicture::isMissingImage() const
|
||||
{
|
||||
return mIsMissingImage;
|
||||
}
|
||||
|
||||
QString QgsLayoutItemPicture::evaluatedPath() const
|
||||
{
|
||||
return mEvaluatedPath;
|
||||
}
|
||||
|
||||
void QgsLayoutItemPicture::shapeChanged()
|
||||
{
|
||||
if ( mMode == FormatSVG && !mLoadingSvg )
|
||||
|
@ -94,6 +94,7 @@ class CORE_EXPORT QgsLayoutItemPicture: public QgsLayoutItem
|
||||
* this value. The path can either be a local path or a remote (http) path.
|
||||
* \returns path for the source image
|
||||
* \see setPicturePath()
|
||||
* \see evaluatedPath()
|
||||
*/
|
||||
QString picturePath() const;
|
||||
|
||||
@ -230,6 +231,23 @@ class CORE_EXPORT QgsLayoutItemPicture: public QgsLayoutItem
|
||||
|
||||
void finalizeRestoreFromXml() override;
|
||||
|
||||
/**
|
||||
* Returns true if the source image is missing and the picture
|
||||
* cannot be rendered.
|
||||
*
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
bool isMissingImage() const;
|
||||
|
||||
/**
|
||||
* Returns the current evaluated picture path, which includes
|
||||
* the result of data defined path overrides.
|
||||
*
|
||||
* \see picturePath()
|
||||
* \since QGIS 3.6
|
||||
*/
|
||||
QString evaluatedPath() const;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -318,6 +336,8 @@ class CORE_EXPORT QgsLayoutItemPicture: public QgsLayoutItem
|
||||
bool mHasExpressionError = false;
|
||||
bool mLoaded = false;
|
||||
bool mLoadingSvg = false;
|
||||
bool mIsMissingImage = false;
|
||||
QString mEvaluatedPath;
|
||||
|
||||
//! Loads an image file into the picture item and redraws the item
|
||||
void loadPicture( const QString &path );
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "qgslayout.h"
|
||||
#include "qgslayoutitemscalebar.h"
|
||||
#include "qgslayoutitemmap.h"
|
||||
#include "qgslayoutitempicture.h"
|
||||
#include "qgsabstractvaliditycheck.h"
|
||||
#include "qgsvaliditycheckcontext.h"
|
||||
#include "layout/qgslayoutvaliditychecks.h"
|
||||
@ -46,6 +47,7 @@ class TestQgsLayoutValidityChecks : public QObject
|
||||
|
||||
void testScaleBarValidity();
|
||||
void testOverviewValidity();
|
||||
void testPictureValidity();
|
||||
|
||||
private:
|
||||
QString mTestDataDir;
|
||||
@ -158,6 +160,63 @@ void TestQgsLayoutValidityChecks::testOverviewValidity()
|
||||
QCOMPARE( res.at( 1 ).type, QgsValidityCheckResult::Warning );
|
||||
}
|
||||
|
||||
void TestQgsLayoutValidityChecks::testPictureValidity()
|
||||
{
|
||||
QgsProject p;
|
||||
QgsLayout l( &p );
|
||||
|
||||
QgsLayoutItemPicture *picture = new QgsLayoutItemPicture( &l );
|
||||
l.addItem( picture );
|
||||
|
||||
QgsLayoutValidityCheckContext context( &l );
|
||||
QgsFeedback f;
|
||||
|
||||
// invalid picture source
|
||||
picture->setPicturePath( QStringLiteral( "blaaaaaaaaaaaaaaaaah" ) );
|
||||
QgsLayoutPictureSourceValidityCheck check;
|
||||
QVERIFY( check.prepareCheck( &context, &f ) );
|
||||
QList< QgsValidityCheckResult > res = check.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 1 );
|
||||
QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
|
||||
|
||||
QgsLayoutPictureSourceValidityCheck check2;
|
||||
picture->setPicturePath( QString() );
|
||||
QVERIFY( check2.prepareCheck( &context, &f ) );
|
||||
res = check2.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 0 );
|
||||
|
||||
QgsLayoutPictureSourceValidityCheck check3;
|
||||
picture->setPicturePath( QStringLiteral( TEST_DATA_DIR ) + "/sample_svg.svg" );
|
||||
QVERIFY( check3.prepareCheck( &context, &f ) );
|
||||
res = check3.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 0 );
|
||||
|
||||
QgsLayoutItemPicture *picture2 = new QgsLayoutItemPicture( &l );
|
||||
l.addItem( picture2 );
|
||||
picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'d:/bad' || 'robot'" ) ) );
|
||||
l.refresh();
|
||||
|
||||
QgsLayoutPictureSourceValidityCheck check4;
|
||||
QVERIFY( check4.prepareCheck( &context, &f ) );
|
||||
res = check4.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 1 );
|
||||
QCOMPARE( res.at( 0 ).type, QgsValidityCheckResult::Warning );
|
||||
|
||||
picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "''" ) ) );
|
||||
l.refresh();
|
||||
QgsLayoutPictureSourceValidityCheck check5;
|
||||
QVERIFY( check5.prepareCheck( &context, &f ) );
|
||||
res = check5.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 0 );
|
||||
|
||||
picture2->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'%1'" ).arg( QStringLiteral( TEST_DATA_DIR ) + "/sam' || 'ple_svg.svg" ) ) );
|
||||
l.refresh();
|
||||
QgsLayoutPictureSourceValidityCheck check6;
|
||||
QVERIFY( check6.prepareCheck( &context, &f ) );
|
||||
res = check6.runCheck( &context, &f );
|
||||
QCOMPARE( res.size(), 0 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
QGSTEST_MAIN( TestQgsLayoutValidityChecks )
|
||||
|
@ -60,6 +60,7 @@ class TestQgsLayoutPicture : public QObject
|
||||
|
||||
void pictureExpression();
|
||||
void pictureInvalidExpression();
|
||||
void valid();
|
||||
|
||||
|
||||
private:
|
||||
@ -422,5 +423,32 @@ void TestQgsLayoutPicture::pictureInvalidExpression()
|
||||
mPicture->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty() );
|
||||
}
|
||||
|
||||
void TestQgsLayoutPicture::valid()
|
||||
{
|
||||
QgsProject p;
|
||||
QgsLayout l( &p );
|
||||
|
||||
QgsLayoutItemPicture *picture = new QgsLayoutItemPicture( &l );
|
||||
l.addItem( picture );
|
||||
|
||||
picture->setPicturePath( mPngImage );
|
||||
QVERIFY( !picture->isMissingImage() );
|
||||
QCOMPARE( picture->evaluatedPath(), mPngImage );
|
||||
|
||||
picture->setPicturePath( QStringLiteral( "bad" ) );
|
||||
QVERIFY( picture->isMissingImage() );
|
||||
QCOMPARE( picture->evaluatedPath(), QStringLiteral( "bad" ) );
|
||||
|
||||
picture->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'%1'" ).arg( mSvgImage ) ) );
|
||||
picture->refreshPicture();
|
||||
QVERIFY( !picture->isMissingImage() );
|
||||
QCOMPARE( picture->evaluatedPath(), mSvgImage );
|
||||
|
||||
picture->dataDefinedProperties().setProperty( QgsLayoutObject::PictureSource, QgsProperty::fromExpression( QStringLiteral( "'bad'" ) ) );
|
||||
picture->refreshPicture();
|
||||
QVERIFY( picture->isMissingImage() );
|
||||
QCOMPARE( picture->evaluatedPath(), QStringLiteral( "bad" ) );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsLayoutPicture )
|
||||
#include "testqgslayoutpicture.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user