mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
[layouts][needs-docs] Add control for whether pages should be
exported, including data defined setting This replaces the 2.x data-defined "number of pages" setting. Instead of requiring users to develop an expression to return the number of pages, instead we allow individual pages to have a data defined control of whether that page should be included in the export. This is more flexible, and works correctly with the mixed page size model for layouts.
This commit is contained in:
parent
3704c48bc0
commit
f649f1f8a7
@ -580,9 +580,6 @@ Emitted when the layout's name is changed.
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
|
@ -1511,6 +1511,9 @@ void QgsLayoutDesignerDialog::exportToRaster()
|
||||
mView->setPaintingEnabled( false );
|
||||
QApplication::setOverrideCursor( Qt::BusyCursor );
|
||||
|
||||
// force a refresh, to e.g. update data defined properties, tables, etc
|
||||
mLayout->refresh();
|
||||
|
||||
QgsLayoutExporter exporter( mLayout );
|
||||
|
||||
QgsLayoutExporter::ImageExportSettings settings;
|
||||
@ -1624,6 +1627,9 @@ void QgsLayoutDesignerDialog::exportToPdf()
|
||||
pdfSettings.rasterizeWholeImage = mLayout->customProperty( QStringLiteral( "rasterise" ), false ).toBool();
|
||||
pdfSettings.forceVectorOutput = mLayout->customProperty( QStringLiteral( "forceVector" ), false ).toBool();
|
||||
|
||||
// force a refresh, to e.g. update data defined properties, tables, etc
|
||||
mLayout->refresh();
|
||||
|
||||
QgsLayoutExporter exporter( mLayout );
|
||||
switch ( exporter.exportToPdf( outputFileName, pdfSettings ) )
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ QgsLayoutPagePropertiesWidget::QgsLayoutPagePropertiesWidget( QWidget *parent, Q
|
||||
mWidthSpin->setValue( mPage->pageSize().width() );
|
||||
mHeightSpin->setValue( mPage->pageSize().height() );
|
||||
mSizeUnitsComboBox->setUnit( mPage->pageSize().units() );
|
||||
mExcludePageCheckBox->setChecked( mPage->excludeFromExports() );
|
||||
|
||||
mPageOrientationComboBox->setCurrentIndex( mPageOrientationComboBox->findData( mPage->orientation() ) );
|
||||
|
||||
@ -59,11 +60,14 @@ QgsLayoutPagePropertiesWidget::QgsLayoutPagePropertiesWidget( QWidget *parent, Q
|
||||
connect( mHeightSpin, static_cast< void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPagePropertiesWidget::updatePageSize );
|
||||
connect( mWidthSpin, static_cast< void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPagePropertiesWidget::setToCustomSize );
|
||||
connect( mHeightSpin, static_cast< void ( QDoubleSpinBox::* )( double )>( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutPagePropertiesWidget::setToCustomSize );
|
||||
connect( mExcludePageCheckBox, &QCheckBox::toggled, this, &QgsLayoutPagePropertiesWidget::excludeExportsToggled );
|
||||
|
||||
connect( mSymbolButton, &QgsSymbolButton::changed, this, &QgsLayoutPagePropertiesWidget::symbolChanged );
|
||||
registerDataDefinedButton( mPaperSizeDDBtn, QgsLayoutObject::PresetPaperSize );
|
||||
registerDataDefinedButton( mWidthDDBtn, QgsLayoutObject::ItemWidth );
|
||||
registerDataDefinedButton( mHeightDDBtn, QgsLayoutObject::ItemHeight );
|
||||
registerDataDefinedButton( mExcludePageDDBtn, QgsLayoutObject::ExcludeFromExports );
|
||||
mExcludePageDDBtn->registerEnabledWidget( mExcludePageCheckBox, false );
|
||||
|
||||
showCurrentPageSize();
|
||||
}
|
||||
@ -155,6 +159,13 @@ void QgsLayoutPagePropertiesWidget::symbolChanged()
|
||||
mPage->layout()->undoStack()->endCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutPagePropertiesWidget::excludeExportsToggled( bool checked )
|
||||
{
|
||||
mPage->beginCommand( !checked ? tr( "Include Page in Exports" ) : tr( "Exclude Page from Exports" ) );
|
||||
mPage->setExcludeFromExports( checked );
|
||||
mPage->endCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutPagePropertiesWidget::showCurrentPageSize()
|
||||
{
|
||||
QgsLayoutSize paperSize = mPage->pageSize();
|
||||
|
@ -48,6 +48,7 @@ class QgsLayoutPagePropertiesWidget : public QgsLayoutItemBaseWidget, private Ui
|
||||
void updatePageSize();
|
||||
void setToCustomSize();
|
||||
void symbolChanged();
|
||||
void excludeExportsToggled( bool checked );
|
||||
|
||||
private:
|
||||
|
||||
|
@ -672,6 +672,3 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
||||
};
|
||||
|
||||
#endif //QGSLAYOUT_H
|
||||
|
||||
|
||||
|
||||
|
@ -236,7 +236,8 @@ class CORE_EXPORT QgsLayoutContext : public QObject
|
||||
bool mPagesVisible = true;
|
||||
|
||||
friend class QgsLayoutExporter;
|
||||
friend class LayoutItemCacheSettingRestorer;
|
||||
friend class TestQgsLayout;
|
||||
friend class LayoutContextPreviewSettingRestorer;
|
||||
|
||||
|
||||
};
|
||||
|
@ -26,6 +26,30 @@
|
||||
#include "gdal.h"
|
||||
#include "cpl_conv.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
class LayoutContextPreviewSettingRestorer
|
||||
{
|
||||
public:
|
||||
|
||||
LayoutContextPreviewSettingRestorer( QgsLayout *layout )
|
||||
: mLayout( layout )
|
||||
, mPreviousSetting( layout->context().mIsPreviewRender )
|
||||
{
|
||||
mLayout->context().mIsPreviewRender = false;
|
||||
}
|
||||
|
||||
~LayoutContextPreviewSettingRestorer()
|
||||
{
|
||||
mLayout->context().mIsPreviewRender = mPreviousSetting;
|
||||
}
|
||||
|
||||
private:
|
||||
QgsLayout *mLayout = nullptr;
|
||||
bool mPreviousSetting = false;
|
||||
};
|
||||
|
||||
///@endcond PRIVATE
|
||||
|
||||
QgsLayoutExporter::QgsLayoutExporter( QgsLayout *layout )
|
||||
: mLayout( layout )
|
||||
{
|
||||
@ -53,6 +77,9 @@ void QgsLayoutExporter::renderPage( QPainter *painter, int page ) const
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
|
||||
QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
|
||||
renderRegion( painter, paperRect );
|
||||
}
|
||||
@ -73,6 +100,9 @@ QImage QgsLayoutExporter::renderPageToImage( int page, QSize imageSize, double d
|
||||
return QImage();
|
||||
}
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
|
||||
QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
|
||||
return renderRegionToImage( paperRect, imageSize, dpi );
|
||||
}
|
||||
@ -85,8 +115,6 @@ class LayoutItemCacheSettingRestorer
|
||||
LayoutItemCacheSettingRestorer( QgsLayout *layout )
|
||||
: mLayout( layout )
|
||||
{
|
||||
mLayout->context().mIsPreviewRender = false;
|
||||
|
||||
const QList< QGraphicsItem * > items = mLayout->items();
|
||||
for ( QGraphicsItem *item : items )
|
||||
{
|
||||
@ -101,8 +129,6 @@ class LayoutItemCacheSettingRestorer
|
||||
{
|
||||
it.key()->setCacheMode( it.value() );
|
||||
}
|
||||
|
||||
mLayout->context().mIsPreviewRender = true;
|
||||
}
|
||||
|
||||
private:
|
||||
@ -122,6 +148,8 @@ void QgsLayoutExporter::renderRegion( QPainter *painter, const QRectF ®ion )
|
||||
|
||||
LayoutItemCacheSettingRestorer cacheRestorer( mLayout );
|
||||
( void )cacheRestorer;
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
|
||||
#if 0 //TODO
|
||||
setSnapLinesVisible( false );
|
||||
@ -138,6 +166,9 @@ void QgsLayoutExporter::renderRegion( QPainter *painter, const QRectF ®ion )
|
||||
|
||||
QImage QgsLayoutExporter::renderRegionToImage( const QRectF ®ion, QSize imageSize, double dpi ) const
|
||||
{
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
|
||||
double resolution = mLayout->context().dpi();
|
||||
double oneInchInLayoutUnits = mLayout->convertToLayoutUnits( QgsLayoutMeasurement( 1, QgsUnitTypes::LayoutInches ) );
|
||||
if ( imageSize.isValid() )
|
||||
@ -219,6 +250,8 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToImage( const QString
|
||||
pageDetails.baseName = fi.baseName();
|
||||
pageDetails.extension = fi.completeSuffix();
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
LayoutContextSettingsRestorer dpiRestorer( mLayout );
|
||||
( void )dpiRestorer;
|
||||
mLayout->context().setDpi( settings.dpi );
|
||||
@ -303,6 +336,8 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdf( const QString &f
|
||||
|
||||
mErrorFileName.clear();
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
LayoutContextSettingsRestorer contextRestorer( mLayout );
|
||||
( void )contextRestorer;
|
||||
mLayout->context().setDpi( settings.dpi );
|
||||
|
@ -831,6 +831,11 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
|
||||
*/
|
||||
void cancelCommand();
|
||||
|
||||
/**
|
||||
* Returns whether the item should be drawn in the current context.
|
||||
*/
|
||||
bool shouldDrawItem() const;
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -1049,11 +1054,6 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
|
||||
*/
|
||||
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
|
||||
|
||||
/**
|
||||
* Returns whether the item should be drawn in the current context.
|
||||
*/
|
||||
bool shouldDrawItem() const;
|
||||
|
||||
/**
|
||||
* Applies any present data defined size overrides to the specified layout \a size.
|
||||
*/
|
||||
|
@ -482,6 +482,10 @@ bool QgsLayoutPageCollection::shouldExportPage( int page ) const
|
||||
return false;
|
||||
}
|
||||
|
||||
QgsLayoutItemPage *pageItem = mPages.at( page );
|
||||
if ( !pageItem->shouldDrawItem() )
|
||||
return false;
|
||||
|
||||
//check all frame items on page
|
||||
QList<QgsLayoutFrame *> frames;
|
||||
itemsOnPage( frames, page );
|
||||
|
@ -14,27 +14,7 @@
|
||||
<string>New Item Properties</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1">
|
||||
<item row="3" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Background</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QgsSymbolButton" name="mSymbolButton">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
@ -56,6 +36,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Background</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
@ -204,6 +191,56 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="mExcludePageCheckBox">
|
||||
<property name="toolTip">
|
||||
<string>If checked, this page will not be included when exporting the layout</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exclude page from exports</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QgsPropertyOverrideButton" name="mExcludePageDDBtn">
|
||||
<property name="text">
|
||||
<string>…</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
@ -244,6 +281,9 @@
|
||||
<tabstop>mHeightSpin</tabstop>
|
||||
<tabstop>mHeightDDBtn</tabstop>
|
||||
<tabstop>mSizeUnitsComboBox</tabstop>
|
||||
<tabstop>mExcludePageCheckBox</tabstop>
|
||||
<tabstop>mExcludePageDDBtn</tabstop>
|
||||
<tabstop>mSymbolButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1018</width>
|
||||
<height>20</height>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
|
@ -613,6 +613,7 @@ void TestQgsLayout::shouldExportPage()
|
||||
QgsLayoutItemPage *page2 = new QgsLayoutItemPage( &l );
|
||||
page2->setPageSize( "A4" );
|
||||
l.pageCollection()->addPage( page2 );
|
||||
l.context().mIsPreviewRender = false;
|
||||
|
||||
QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( &l );
|
||||
//frame on page 1
|
||||
@ -645,6 +646,33 @@ void TestQgsLayout::shouldExportPage()
|
||||
|
||||
QVERIFY( l.pageCollection()->shouldExportPage( 0 ) );
|
||||
QVERIFY( !l.pageCollection()->shouldExportPage( 1 ) );
|
||||
|
||||
// get rid of frames
|
||||
l.removeItem( frame1 );
|
||||
l.removeItem( frame2 );
|
||||
l.removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
QgsApplication::sendPostedEvents( nullptr, QEvent::DeferredDelete );
|
||||
|
||||
QVERIFY( l.pageCollection()->shouldExportPage( 0 ) );
|
||||
QVERIFY( l.pageCollection()->shouldExportPage( 1 ) );
|
||||
|
||||
// explicitly set exclude from exports
|
||||
l.pageCollection()->page( 0 )->setExcludeFromExports( true );
|
||||
QVERIFY( !l.pageCollection()->shouldExportPage( 0 ) );
|
||||
QVERIFY( l.pageCollection()->shouldExportPage( 1 ) );
|
||||
|
||||
l.pageCollection()->page( 0 )->setExcludeFromExports( false );
|
||||
l.pageCollection()->page( 1 )->setExcludeFromExports( true );
|
||||
QVERIFY( l.pageCollection()->shouldExportPage( 0 ) );
|
||||
QVERIFY( !l.pageCollection()->shouldExportPage( 1 ) );
|
||||
|
||||
l.pageCollection()->page( 1 )->setExcludeFromExports( false );
|
||||
l.pageCollection()->page( 0 )->dataDefinedProperties().setProperty( QgsLayoutObject::ExcludeFromExports, QgsProperty::fromExpression( "1" ) );
|
||||
l.pageCollection()->page( 1 )->dataDefinedProperties().setProperty( QgsLayoutObject::ExcludeFromExports, QgsProperty::fromValue( true ) );
|
||||
l.refresh();
|
||||
QVERIFY( !l.pageCollection()->shouldExportPage( 0 ) );
|
||||
QVERIFY( !l.pageCollection()->shouldExportPage( 1 ) );
|
||||
}
|
||||
|
||||
void TestQgsLayout::pageIsEmpty()
|
||||
|
@ -317,6 +317,52 @@ class TestQgsLayoutExporter(unittest.TestCase):
|
||||
self.assertAlmostEqual(values[4], 1925.000000000000, 2)
|
||||
self.assertAlmostEqual(values[5], 3050.000000000000, 2)
|
||||
|
||||
def testExcludePagesImage(self):
|
||||
l = QgsLayout(QgsProject.instance())
|
||||
l.initializeDefaults()
|
||||
# add a second page
|
||||
page2 = QgsLayoutItemPage(l)
|
||||
page2.setPageSize('A5')
|
||||
l.pageCollection().addPage(page2)
|
||||
|
||||
exporter = QgsLayoutExporter(l)
|
||||
# setup settings
|
||||
settings = QgsLayoutExporter.ImageExportSettings()
|
||||
settings.dpi = 80
|
||||
settings.generateWorldFile = False
|
||||
|
||||
rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export.png')
|
||||
details = QgsLayoutExporter.PageExportDetails()
|
||||
details.directory = self.basetestpath
|
||||
details.baseName = 'test_exclude_export'
|
||||
details.extension = 'png'
|
||||
details.page = 0
|
||||
|
||||
self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.Success)
|
||||
self.assertTrue(os.path.exists(exporter.generateFileName(details)))
|
||||
details.page = 1
|
||||
self.assertTrue(os.path.exists(exporter.generateFileName(details)))
|
||||
|
||||
# exclude a page
|
||||
l.pageCollection().page(0).setExcludeFromExports(True)
|
||||
rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export_excluded.png')
|
||||
details.baseName = 'test_exclude_export_excluded'
|
||||
details.page = 0
|
||||
self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.Success)
|
||||
self.assertFalse(os.path.exists(exporter.generateFileName(details)))
|
||||
details.page = 1
|
||||
self.assertTrue(os.path.exists(exporter.generateFileName(details)))
|
||||
|
||||
# exclude second page
|
||||
l.pageCollection().page(1).setExcludeFromExports(True)
|
||||
rendered_file_path = os.path.join(self.basetestpath, 'test_exclude_export_excluded_all.png')
|
||||
details.baseName = 'test_exclude_export_excluded_all'
|
||||
details.page = 0
|
||||
self.assertEqual(exporter.exportToImage(rendered_file_path, settings), QgsLayoutExporter.Success)
|
||||
self.assertFalse(os.path.exists(exporter.generateFileName(details)))
|
||||
details.page = 1
|
||||
self.assertFalse(os.path.exists(exporter.generateFileName(details)))
|
||||
|
||||
def testPageFileName(self):
|
||||
l = QgsLayout(QgsProject.instance())
|
||||
exporter = QgsLayoutExporter(l)
|
||||
|
Loading…
x
Reference in New Issue
Block a user