mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
Restore direct print actions
This commit is contained in:
parent
a730eb7a95
commit
4e45639c45
@ -290,6 +290,53 @@ to the error description.
|
||||
.. seealso:: :py:func:`exportToPdf()`
|
||||
%End
|
||||
|
||||
|
||||
struct PrintExportSettings
|
||||
{
|
||||
PrintExportSettings();
|
||||
%Docstring
|
||||
Constructor for PrintExportSettings
|
||||
%End
|
||||
|
||||
double dpi;
|
||||
%Docstring
|
||||
Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
|
||||
%End
|
||||
|
||||
bool rasterizeWholeImage;
|
||||
%Docstring
|
||||
Set to true to force whole layout to be rasterized while exporting.
|
||||
|
||||
This option is mutually exclusive with forceVectorOutput.
|
||||
%End
|
||||
|
||||
QgsLayoutRenderContext::Flags flags;
|
||||
%Docstring
|
||||
Layout context flags, which control how the export will be created.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
ExportResult print( QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &settings );
|
||||
%Docstring
|
||||
Prints the layout to a ``printer``, using the specified export ``settings``.
|
||||
|
||||
Returns a result code indicating whether the export was successful or an
|
||||
error was encountered.
|
||||
%End
|
||||
|
||||
static ExportResult print( QgsAbstractLayoutIterator *iterator, QPrinter &printer,
|
||||
const QgsLayoutExporter::PrintExportSettings &settings,
|
||||
QString &error /Out/, QgsFeedback *feedback = 0 );
|
||||
%Docstring
|
||||
Exports a layout ``iterator`` to a ``printer``, with the specified export ``settings``.
|
||||
|
||||
Returns a result code indicating whether the export was successful or an
|
||||
error was encountered. If an error was obtained then ``error`` will be set
|
||||
to the error description.
|
||||
%End
|
||||
|
||||
|
||||
struct SvgExportSettings
|
||||
{
|
||||
SvgExportSettings();
|
||||
|
@ -73,6 +73,9 @@
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QProgressDialog>
|
||||
#include <QPrinter>
|
||||
#include <QPrintDialog>
|
||||
#include <QPageSetupDialog>
|
||||
#ifdef Q_OS_MACX
|
||||
#include <ApplicationServices/ApplicationServices.h>
|
||||
#endif
|
||||
@ -195,6 +198,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
||||
connect( mActionLayoutManager, &QAction::triggered, this, &QgsLayoutDesignerDialog::showManager );
|
||||
connect( mActionRemoveLayout, &QAction::triggered, this, &QgsLayoutDesignerDialog::deleteLayout );
|
||||
|
||||
connect( mActionPrint, &QAction::triggered, this, &QgsLayoutDesignerDialog::print );
|
||||
connect( mActionExportAsImage, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToRaster );
|
||||
connect( mActionExportAsPDF, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToPdf );
|
||||
connect( mActionExportAsSVG, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportToSvg );
|
||||
@ -226,6 +230,9 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
|
||||
connect( mActionExportReportAsImage, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportReportToRaster );
|
||||
connect( mActionExportReportAsSVG, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportReportToSvg );
|
||||
connect( mActionExportReportAsPDF, &QAction::triggered, this, &QgsLayoutDesignerDialog::exportReportToPdf );
|
||||
connect( mActionPrintReport, &QAction::triggered, this, &QgsLayoutDesignerDialog::printReport );
|
||||
|
||||
connect( mActionPageSetup, &QAction::triggered, this, &QgsLayoutDesignerDialog::pageSetup );
|
||||
|
||||
mView = new QgsLayoutView();
|
||||
//mView->setMapCanvas( mQgis->mapCanvas() );
|
||||
@ -882,6 +889,10 @@ void QgsLayoutDesignerDialog::showItemOptions( QgsLayoutItem *item, bool bringPa
|
||||
if ( ! widget )
|
||||
return;
|
||||
|
||||
|
||||
if ( QgsLayoutPagePropertiesWidget *ppWidget = qobject_cast< QgsLayoutPagePropertiesWidget * >( widget.get() ) )
|
||||
connect( ppWidget, &QgsLayoutPagePropertiesWidget::pageOrientationChanged, this, &QgsLayoutDesignerDialog::pageOrientationChanged );
|
||||
|
||||
widget->setDockMode( true );
|
||||
connect( item, &QgsLayoutItem::destroyed, widget.get(), [this]
|
||||
{
|
||||
@ -1573,6 +1584,102 @@ void QgsLayoutDesignerDialog::deleteLayout()
|
||||
close();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::print()
|
||||
{
|
||||
if ( containsWmsLayers() )
|
||||
{
|
||||
showWmsPrintingWarning();
|
||||
}
|
||||
|
||||
if ( requiresRasterization() )
|
||||
{
|
||||
showRasterizationWarning();
|
||||
}
|
||||
|
||||
if ( currentLayout()->pageCollection()->pageCount() == 0 )
|
||||
return;
|
||||
|
||||
// get orientation from first page
|
||||
QgsLayoutItemPage::Orientation orientation = currentLayout()->pageCollection()->page( 0 )->orientation();
|
||||
|
||||
//set printer page orientation
|
||||
setPrinterPageOrientation( orientation );
|
||||
|
||||
QPrintDialog printDialog( printer(), nullptr );
|
||||
if ( printDialog.exec() != QDialog::Accepted )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
mView->setPaintingEnabled( false );
|
||||
QApplication::setOverrideCursor( Qt::BusyCursor );
|
||||
|
||||
QgsLayoutExporter::PrintExportSettings printSettings;
|
||||
printSettings.rasterizeWholeImage = mLayout->customProperty( QStringLiteral( "rasterize" ), false ).toBool();
|
||||
|
||||
// force a refresh, to e.g. update data defined properties, tables, etc
|
||||
mLayout->refresh();
|
||||
|
||||
QgsLayoutExporter exporter( mLayout );
|
||||
QString printerName = printer()->printerName();
|
||||
switch ( exporter.print( *printer(), printSettings ) )
|
||||
{
|
||||
case QgsLayoutExporter::Success:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Successfully printed layout to %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Successfully printed layout" );
|
||||
}
|
||||
mMessageBar->pushMessage( tr( "Print layout" ),
|
||||
message,
|
||||
QgsMessageBar::SUCCESS, 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::PrintError:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Could not create print device for %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Could not create print device" );
|
||||
}
|
||||
QMessageBox::warning( this, tr( "Print layout" ),
|
||||
message,
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::MemoryError:
|
||||
QMessageBox::warning( this, tr( "Memory Allocation Error" ),
|
||||
tr( "Printing the layout "
|
||||
"resulted in a memory overflow.\n\n"
|
||||
"Please try a lower resolution or a smaller paper size." ),
|
||||
QMessageBox::Ok, QMessageBox::Ok );
|
||||
break;
|
||||
|
||||
case QgsLayoutExporter::FileError:
|
||||
case QgsLayoutExporter::SvgLayerError:
|
||||
case QgsLayoutExporter::IteratorError:
|
||||
case QgsLayoutExporter::Canceled:
|
||||
// no meaning for PDF exports, will not be encountered
|
||||
break;
|
||||
}
|
||||
|
||||
mView->setPaintingEnabled( true );
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::exportToRaster()
|
||||
{
|
||||
if ( containsWmsLayers() )
|
||||
@ -2032,8 +2139,132 @@ void QgsLayoutDesignerDialog::atlasLast()
|
||||
|
||||
void QgsLayoutDesignerDialog::printAtlas()
|
||||
{
|
||||
QgsLayoutAtlas *printAtlas = atlas();
|
||||
if ( !printAtlas || !printAtlas->enabled() )
|
||||
return;
|
||||
|
||||
loadAtlasPredefinedScalesFromProject();
|
||||
//TODO
|
||||
|
||||
if ( containsWmsLayers() )
|
||||
{
|
||||
showWmsPrintingWarning();
|
||||
}
|
||||
|
||||
if ( requiresRasterization() )
|
||||
{
|
||||
showRasterizationWarning();
|
||||
}
|
||||
|
||||
if ( currentLayout()->pageCollection()->pageCount() == 0 )
|
||||
return;
|
||||
|
||||
// get orientation from first page
|
||||
QgsLayoutItemPage::Orientation orientation = currentLayout()->pageCollection()->page( 0 )->orientation();
|
||||
|
||||
//set printer page orientation
|
||||
setPrinterPageOrientation( orientation );
|
||||
|
||||
QPrintDialog printDialog( printer(), nullptr );
|
||||
if ( printDialog.exec() != QDialog::Accepted )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mView->setPaintingEnabled( false );
|
||||
QApplication::setOverrideCursor( Qt::BusyCursor );
|
||||
|
||||
QgsLayoutExporter::PrintExportSettings printSettings;
|
||||
printSettings.rasterizeWholeImage = mLayout->customProperty( QStringLiteral( "rasterize" ), false ).toBool();
|
||||
|
||||
QString error;
|
||||
std::unique_ptr< QgsFeedback > feedback = qgis::make_unique< QgsFeedback >();
|
||||
std::unique_ptr< QProgressDialog > progressDialog = qgis::make_unique< QProgressDialog >( tr( "Printing maps..." ), tr( "Abort" ), 0, 100, this );
|
||||
progressDialog->setWindowTitle( tr( "Printing Atlas" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double progress )
|
||||
{
|
||||
progressDialog->setValue( progress );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// For some reason on Windows hasPendingEvents() always return true,
|
||||
// but one iteration is actually enough on Windows to get good interactivity
|
||||
// whereas on Linux we must allow for far more iterations.
|
||||
// For safety limit the number of iterations
|
||||
int nIters = 0;
|
||||
while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
|
||||
#endif
|
||||
{
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
} );
|
||||
connect( progressDialog.get(), &QProgressDialog::canceled, this, [ & ]
|
||||
{
|
||||
feedback->cancel();
|
||||
} );
|
||||
|
||||
QString printerName = printer()->printerName();
|
||||
switch ( QgsLayoutExporter::print( printAtlas, *printer(), printSettings, error, feedback.get() ) )
|
||||
{
|
||||
case QgsLayoutExporter::Success:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Successfully printed atlas to %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Successfully printed atlas" );
|
||||
}
|
||||
mMessageBar->pushMessage( tr( "Print atlas" ),
|
||||
message,
|
||||
QgsMessageBar::SUCCESS, 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::PrintError:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Could not create print device for %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Could not create print device" );
|
||||
}
|
||||
QMessageBox::warning( this, tr( "Print atlas" ),
|
||||
message,
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::MemoryError:
|
||||
QMessageBox::warning( this, tr( "Memory Allocation Error" ),
|
||||
tr( "Printing the layout "
|
||||
"resulted in a memory overflow.\n\n"
|
||||
"Please try a lower resolution or a smaller paper size." ),
|
||||
QMessageBox::Ok, QMessageBox::Ok );
|
||||
break;
|
||||
|
||||
case QgsLayoutExporter::IteratorError:
|
||||
QMessageBox::warning( this, tr( "Print Atlas" ),
|
||||
tr( "Error encountered while printing atlas" ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
break;
|
||||
|
||||
case QgsLayoutExporter::FileError:
|
||||
case QgsLayoutExporter::SvgLayerError:
|
||||
case QgsLayoutExporter::Canceled:
|
||||
// no meaning for PDF exports, will not be encountered
|
||||
break;
|
||||
}
|
||||
|
||||
mView->setPaintingEnabled( true );
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::exportAtlasToRaster()
|
||||
@ -2934,6 +3165,112 @@ void QgsLayoutDesignerDialog::exportReportToPdf()
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::printReport()
|
||||
{
|
||||
QPrintDialog printDialog( printer(), nullptr );
|
||||
if ( printDialog.exec() != QDialog::Accepted )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mView->setPaintingEnabled( false );
|
||||
QApplication::setOverrideCursor( Qt::BusyCursor );
|
||||
|
||||
QgsLayoutExporter::PrintExportSettings printSettings;
|
||||
if ( mLayout )
|
||||
printSettings.rasterizeWholeImage = mLayout->customProperty( QStringLiteral( "rasterize" ), false ).toBool();
|
||||
|
||||
QString error;
|
||||
std::unique_ptr< QgsFeedback > feedback = qgis::make_unique< QgsFeedback >();
|
||||
std::unique_ptr< QProgressDialog > progressDialog = qgis::make_unique< QProgressDialog >( tr( "Printing maps..." ), tr( "Abort" ), 0, 0, this );
|
||||
progressDialog->setWindowTitle( tr( "Printing Report" ) );
|
||||
connect( feedback.get(), &QgsFeedback::progressChanged, this, [ & ]( double )
|
||||
{
|
||||
//progressDialog->setValue( progress );
|
||||
progressDialog->setLabelText( feedback->property( "progress" ).toString() ) ;
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
// For some reason on Windows hasPendingEvents() always return true,
|
||||
// but one iteration is actually enough on Windows to get good interactivity
|
||||
// whereas on Linux we must allow for far more iterations.
|
||||
// For safety limit the number of iterations
|
||||
int nIters = 0;
|
||||
while ( QCoreApplication::hasPendingEvents() && ++nIters < 100 )
|
||||
#endif
|
||||
{
|
||||
QCoreApplication::processEvents();
|
||||
}
|
||||
|
||||
} );
|
||||
connect( progressDialog.get(), &QProgressDialog::canceled, this, [ & ]
|
||||
{
|
||||
feedback->cancel();
|
||||
} );
|
||||
|
||||
QString printerName = printer()->printerName();
|
||||
switch ( QgsLayoutExporter::print( dynamic_cast< QgsReport * >( mMasterLayout ), *printer(), printSettings, error, feedback.get() ) )
|
||||
{
|
||||
case QgsLayoutExporter::Success:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Successfully printed report to %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Successfully printed report" );
|
||||
}
|
||||
mMessageBar->pushMessage( tr( "Print report" ),
|
||||
message,
|
||||
QgsMessageBar::SUCCESS, 0 );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::PrintError:
|
||||
{
|
||||
QString message;
|
||||
if ( !printerName.isEmpty() )
|
||||
{
|
||||
message = tr( "Could not create print device for %1" ).arg( printerName );
|
||||
}
|
||||
else
|
||||
{
|
||||
message = tr( "Could not create print device" );
|
||||
}
|
||||
QMessageBox::warning( this, tr( "Print report" ),
|
||||
message,
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsLayoutExporter::MemoryError:
|
||||
QMessageBox::warning( this, tr( "Memory Allocation Error" ),
|
||||
tr( "Printing the report"
|
||||
"resulted in a memory overflow.\n\n"
|
||||
"Please try a lower resolution or a smaller paper size." ),
|
||||
QMessageBox::Ok, QMessageBox::Ok );
|
||||
break;
|
||||
|
||||
case QgsLayoutExporter::IteratorError:
|
||||
QMessageBox::warning( this, tr( "Print Report" ),
|
||||
tr( "Error encountered while printing report" ),
|
||||
QMessageBox::Ok,
|
||||
QMessageBox::Ok );
|
||||
break;
|
||||
|
||||
case QgsLayoutExporter::FileError:
|
||||
case QgsLayoutExporter::SvgLayerError:
|
||||
case QgsLayoutExporter::Canceled:
|
||||
// no meaning for PDF exports, will not be encountered
|
||||
break;
|
||||
}
|
||||
|
||||
mView->setPaintingEnabled( true );
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::showReportSettings()
|
||||
{
|
||||
if ( !mReportDock )
|
||||
@ -2947,6 +3284,25 @@ void QgsLayoutDesignerDialog::showReportSettings()
|
||||
mReportDock->raise();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::pageSetup()
|
||||
{
|
||||
if ( currentLayout() && currentLayout()->pageCollection()->pageCount() > 0 )
|
||||
{
|
||||
// get orientation from first page
|
||||
QgsLayoutItemPage::Orientation orientation = currentLayout()->pageCollection()->page( 0 )->orientation();
|
||||
//set printer page orientation
|
||||
setPrinterPageOrientation( orientation );
|
||||
}
|
||||
|
||||
QPageSetupDialog pageSetupDialog( printer(), this );
|
||||
pageSetupDialog.exec();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::pageOrientationChanged()
|
||||
{
|
||||
mSetPageOrientation = false;
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::paste()
|
||||
{
|
||||
QPointF pt = mView->mapFromGlobal( QCursor::pos() );
|
||||
@ -3078,6 +3434,8 @@ void QgsLayoutDesignerDialog::createReportWidget()
|
||||
QgsReportOrganizerWidget *reportWidget = new QgsReportOrganizerWidget( mReportDock, this, report );
|
||||
reportWidget->setMessageBar( mMessageBar );
|
||||
mReportDock->setWidget( reportWidget );
|
||||
mReportDock->show();
|
||||
mReportDock->raise();
|
||||
|
||||
mReportToolbar->show();
|
||||
|
||||
@ -3087,9 +3445,10 @@ void QgsLayoutDesignerDialog::createReportWidget()
|
||||
void QgsLayoutDesignerDialog::initializeRegistry()
|
||||
{
|
||||
sInitializedRegistry = true;
|
||||
auto createPageWidget = ( []( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
|
||||
auto createPageWidget = ( [this]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
|
||||
{
|
||||
return new QgsLayoutPagePropertiesWidget( nullptr, item );
|
||||
std::unique_ptr< QgsLayoutPagePropertiesWidget > newWidget = qgis::make_unique< QgsLayoutPagePropertiesWidget >( nullptr, item );
|
||||
return newWidget.release();
|
||||
} );
|
||||
|
||||
QgsGui::layoutItemGuiRegistry()->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPage, QObject::tr( "Page" ), QIcon(), createPageWidget, nullptr, QString(), false, QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools ) );
|
||||
@ -3573,6 +3932,35 @@ void QgsLayoutDesignerDialog::toggleActions( bool layoutAvailable )
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::setPrinterPageOrientation( QgsLayoutItemPage::Orientation orientation )
|
||||
{
|
||||
if ( !mSetPageOrientation )
|
||||
{
|
||||
switch ( orientation )
|
||||
{
|
||||
case QgsLayoutItemPage::Landscape:
|
||||
printer()->setOrientation( QPrinter::Landscape );
|
||||
break;
|
||||
|
||||
case QgsLayoutItemPage::Portrait:
|
||||
printer()->setOrientation( QPrinter::Portrait );
|
||||
break;
|
||||
}
|
||||
|
||||
mSetPageOrientation = true;
|
||||
}
|
||||
}
|
||||
|
||||
QPrinter *QgsLayoutDesignerDialog::printer()
|
||||
{
|
||||
//only create the printer on demand - creating a printer object can be very slow
|
||||
//due to QTBUG-3033
|
||||
if ( !mPrinter )
|
||||
mPrinter = qgis::make_unique< QPrinter >();
|
||||
|
||||
return mPrinter.get();
|
||||
}
|
||||
|
||||
void QgsLayoutDesignerDialog::selectItems( const QList<QgsLayoutItem *> items )
|
||||
{
|
||||
for ( QGraphicsItem *item : items )
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "ui_qgslayoutdesignerbase.h"
|
||||
#include "qgslayoutdesignerinterface.h"
|
||||
#include "qgslayoutexporter.h"
|
||||
#include "qgslayoutpagecollection.h"
|
||||
#include <QToolButton>
|
||||
|
||||
class QgsLayoutDesignerDialog;
|
||||
@ -304,6 +305,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
void showManager();
|
||||
void renameLayout();
|
||||
void deleteLayout();
|
||||
void print();
|
||||
void exportToRaster();
|
||||
void exportToPdf();
|
||||
void exportToSvg();
|
||||
@ -322,7 +324,14 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
void exportReportToRaster();
|
||||
void exportReportToSvg();
|
||||
void exportReportToPdf();
|
||||
void printReport();
|
||||
void showReportSettings();
|
||||
|
||||
void pageSetup();
|
||||
|
||||
//! Sets the printer page orientation when the page orientation changes
|
||||
void pageOrientationChanged();
|
||||
|
||||
private:
|
||||
|
||||
static bool sInitializedRegistry;
|
||||
@ -406,6 +415,10 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
|
||||
QComboBox *mAtlasPageComboBox = nullptr;
|
||||
|
||||
//! Page & Printer Setup
|
||||
std::unique_ptr< QPrinter > mPrinter;
|
||||
bool mSetPageOrientation = false;
|
||||
|
||||
//! Save window state
|
||||
void saveWindowState();
|
||||
|
||||
@ -462,6 +475,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
|
||||
QgsLayoutAtlas *atlas();
|
||||
|
||||
void toggleActions( bool layoutAvailable );
|
||||
|
||||
void setPrinterPageOrientation( QgsLayoutItemPage::Orientation orientation );
|
||||
QPrinter *printer();
|
||||
};
|
||||
|
||||
#endif // QGSLAYOUTDESIGNERDIALOG_H
|
||||
|
@ -165,6 +165,8 @@ void QgsLayoutPagePropertiesWidget::updatePageSize()
|
||||
mPage->layout()->pageCollection()->reflow();
|
||||
mPage->layout()->pageCollection()->endPageSizeChange();
|
||||
mPage->layout()->undoStack()->endMacro();
|
||||
|
||||
emit pageOrientationChanged();
|
||||
}
|
||||
|
||||
void QgsLayoutPagePropertiesWidget::setToCustomSize()
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "qgslayoutpoint.h"
|
||||
#include "qgslayoutitemwidget.h"
|
||||
#include "qgslayoutmeasurementconverter.h"
|
||||
#include "qgslayoutpagecollection.h"
|
||||
|
||||
class QgsLayoutItem;
|
||||
class QgsLayoutItemPage;
|
||||
@ -41,6 +42,11 @@ class QgsLayoutPagePropertiesWidget : public QgsLayoutItemBaseWidget, private Ui
|
||||
*/
|
||||
QgsLayoutPagePropertiesWidget( QWidget *parent, QgsLayoutItem *page );
|
||||
|
||||
signals:
|
||||
|
||||
//! Is emitted when page orientation changes
|
||||
void pageOrientationChanged();
|
||||
|
||||
private slots:
|
||||
|
||||
void pageSizeChanged( int index );
|
||||
|
@ -620,6 +620,119 @@ QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToPdfs( QgsAbstractLayo
|
||||
return Success;
|
||||
}
|
||||
|
||||
QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &s )
|
||||
{
|
||||
if ( !mLayout )
|
||||
return PrintError;
|
||||
|
||||
QgsLayoutExporter::PrintExportSettings settings = s;
|
||||
if ( settings.dpi <= 0 )
|
||||
settings.dpi = mLayout->renderContext().dpi();
|
||||
|
||||
mErrorFileName.clear();
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( mLayout );
|
||||
( void )restorer;
|
||||
LayoutContextSettingsRestorer contextRestorer( mLayout );
|
||||
( void )contextRestorer;
|
||||
mLayout->renderContext().setDpi( settings.dpi );
|
||||
|
||||
// If we are not printing as raster, temporarily disable advanced effects
|
||||
// as QPrinter does not support composition modes and can result
|
||||
// in items missing from the output
|
||||
mLayout->renderContext().setFlag( QgsLayoutRenderContext::FlagUseAdvancedEffects, !settings.rasterizeWholeImage );
|
||||
|
||||
preparePrint( mLayout, printer, true );
|
||||
QPainter p;
|
||||
if ( !p.begin( &printer ) )
|
||||
{
|
||||
//error beginning print
|
||||
return PrintError;
|
||||
}
|
||||
|
||||
ExportResult result = printPrivate( printer, p, false, settings.dpi, settings.rasterizeWholeImage );
|
||||
p.end();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QgsLayoutExporter::ExportResult QgsLayoutExporter::print( QgsAbstractLayoutIterator *iterator, QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &s, QString &error, QgsFeedback *feedback )
|
||||
{
|
||||
error.clear();
|
||||
|
||||
if ( !iterator->beginRender() )
|
||||
return IteratorError;
|
||||
|
||||
PrintExportSettings settings = s;
|
||||
|
||||
QPainter p;
|
||||
|
||||
int total = iterator->count();
|
||||
double step = total > 0 ? 100.0 / total : 100.0;
|
||||
int i = 0;
|
||||
bool first = true;
|
||||
while ( iterator->next() )
|
||||
{
|
||||
if ( feedback )
|
||||
{
|
||||
if ( total > 0 )
|
||||
feedback->setProperty( "progress", QObject::tr( "Printing %1 of %2" ).arg( i + 1 ).arg( total ) );
|
||||
else
|
||||
feedback->setProperty( "progress", QObject::tr( "Printing section %1" ).arg( i + 1 ).arg( total ) );
|
||||
feedback->setProgress( step * i );
|
||||
}
|
||||
if ( feedback && feedback->isCanceled() )
|
||||
{
|
||||
iterator->endRender();
|
||||
return Canceled;
|
||||
}
|
||||
|
||||
if ( s.dpi <= 0 )
|
||||
settings.dpi = iterator->layout()->renderContext().dpi();
|
||||
|
||||
LayoutContextPreviewSettingRestorer restorer( iterator->layout() );
|
||||
( void )restorer;
|
||||
LayoutContextSettingsRestorer contextRestorer( iterator->layout() );
|
||||
( void )contextRestorer;
|
||||
iterator->layout()->renderContext().setDpi( settings.dpi );
|
||||
|
||||
// If we are not printing as raster, temporarily disable advanced effects
|
||||
// as QPrinter does not support composition modes and can result
|
||||
// in items missing from the output
|
||||
iterator->layout()->renderContext().setFlag( QgsLayoutRenderContext::FlagUseAdvancedEffects, !settings.rasterizeWholeImage );
|
||||
|
||||
if ( first )
|
||||
{
|
||||
preparePrint( iterator->layout(), printer, true );
|
||||
|
||||
if ( !p.begin( &printer ) )
|
||||
{
|
||||
//error beginning print
|
||||
return PrintError;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayoutExporter exporter( iterator->layout() );
|
||||
|
||||
ExportResult result = exporter.printPrivate( printer, p, !first, settings.dpi, settings.rasterizeWholeImage );
|
||||
if ( result != Success )
|
||||
{
|
||||
iterator->endRender();
|
||||
return result;
|
||||
}
|
||||
first = false;
|
||||
i++;
|
||||
}
|
||||
|
||||
if ( feedback )
|
||||
{
|
||||
feedback->setProgress( 100 );
|
||||
}
|
||||
|
||||
iterator->endRender();
|
||||
return Success;
|
||||
}
|
||||
|
||||
QgsLayoutExporter::ExportResult QgsLayoutExporter::exportToSvg( const QString &filePath, const QgsLayoutExporter::SvgExportSettings &s )
|
||||
{
|
||||
if ( !mLayout )
|
||||
|
@ -299,6 +299,52 @@ class CORE_EXPORT QgsLayoutExporter
|
||||
const QgsLayoutExporter::PdfExportSettings &settings,
|
||||
QString &error SIP_OUT, QgsFeedback *feedback = nullptr );
|
||||
|
||||
|
||||
//! Contains settings relating to printing layouts
|
||||
struct PrintExportSettings
|
||||
{
|
||||
//! Constructor for PrintExportSettings
|
||||
PrintExportSettings()
|
||||
: flags( QgsLayoutRenderContext::FlagAntialiasing | QgsLayoutRenderContext::FlagUseAdvancedEffects )
|
||||
{}
|
||||
|
||||
//! Resolution to export layout at. If dpi <= 0 the default layout dpi will be used.
|
||||
double dpi = -1;
|
||||
|
||||
/**
|
||||
* Set to true to force whole layout to be rasterized while exporting.
|
||||
*
|
||||
* This option is mutually exclusive with forceVectorOutput.
|
||||
*/
|
||||
bool rasterizeWholeImage = false;
|
||||
|
||||
/**
|
||||
* Layout context flags, which control how the export will be created.
|
||||
*/
|
||||
QgsLayoutRenderContext::Flags flags = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Prints the layout to a \a printer, using the specified export \a settings.
|
||||
*
|
||||
* Returns a result code indicating whether the export was successful or an
|
||||
* error was encountered.
|
||||
*/
|
||||
ExportResult print( QPrinter &printer, const QgsLayoutExporter::PrintExportSettings &settings );
|
||||
|
||||
/**
|
||||
* Exports a layout \a iterator to a \a printer, with the specified export \a settings.
|
||||
*
|
||||
* Returns a result code indicating whether the export was successful or an
|
||||
* error was encountered. If an error was obtained then \a error will be set
|
||||
* to the error description.
|
||||
*/
|
||||
static ExportResult print( QgsAbstractLayoutIterator *iterator, QPrinter &printer,
|
||||
const QgsLayoutExporter::PrintExportSettings &settings,
|
||||
QString &error SIP_OUT, QgsFeedback *feedback = nullptr );
|
||||
|
||||
|
||||
//! Contains settings relating to exporting layouts to SVG
|
||||
struct SvgExportSettings
|
||||
{
|
||||
|
@ -6,7 +6,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1484</width>
|
||||
<width>2180</width>
|
||||
<height>609</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -72,6 +72,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="mActionAddPages"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="mActionPrint"/>
|
||||
<addaction name="mActionExportAsImage"/>
|
||||
<addaction name="mActionExportAsSVG"/>
|
||||
<addaction name="mActionExportAsPDF"/>
|
||||
@ -97,7 +98,7 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1484</width>
|
||||
<width>2180</width>
|
||||
<height>42</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -123,6 +124,9 @@
|
||||
<addaction name="mActionExportAsSVG"/>
|
||||
<addaction name="mActionExportAsPDF"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="mActionPageSetup"/>
|
||||
<addaction name="mActionPrint"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="mActionClose"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="mItemMenu">
|
||||
@ -346,6 +350,7 @@
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="mActionPrintReport"/>
|
||||
<addaction name="mActionExportReportAsImage"/>
|
||||
<addaction name="mActionExportReportAsSVG"/>
|
||||
<addaction name="mActionExportReportAsPDF"/>
|
||||
@ -1435,6 +1440,47 @@
|
||||
<string>Report Settings</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionPrint">
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionFilePrint.svg</normaloff>:/images/themes/default/mActionFilePrint.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Print...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Print Layout</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+P</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionPrintReport">
|
||||
<property name="icon">
|
||||
<iconset resource="../../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionFilePrint.svg</normaloff>:/images/themes/default/mActionFilePrint.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Print Report...</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Print Report</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionPageSetup">
|
||||
<property name="text">
|
||||
<string>Pa&ge Setup…</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Page setup</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+P</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../../../images/images.qrc"/>
|
||||
|
@ -41,6 +41,7 @@ from qgis.core import (QgsMultiRenderChecker,
|
||||
QgsReport)
|
||||
from qgis.PyQt.QtCore import QSize, QSizeF, QDir, QRectF, Qt
|
||||
from qgis.PyQt.QtGui import QImage, QPainter
|
||||
from qgis.PyQt.QtPrintSupport import QPrinter
|
||||
from qgis.PyQt.QtSvg import QSvgRenderer, QSvgGenerator
|
||||
|
||||
from qgis.testing import start_app, unittest
|
||||
@ -484,6 +485,61 @@ class TestQgsLayoutExporter(unittest.TestCase):
|
||||
self.assertTrue(self.checkImage('exporttosvglayered_page1', 'exporttopdfdpi_page1', rendered_page_1, size_tolerance=1))
|
||||
self.assertTrue(self.checkImage('exporttosvglayered_page2', 'exporttopdfdpi_page2', rendered_page_2, size_tolerance=1))
|
||||
|
||||
def testPrint(self):
|
||||
l = QgsLayout(QgsProject.instance())
|
||||
l.initializeDefaults()
|
||||
|
||||
# add a second page
|
||||
page2 = QgsLayoutItemPage(l)
|
||||
page2.setPageSize('A5')
|
||||
l.pageCollection().addPage(page2)
|
||||
|
||||
# add some items
|
||||
item1 = QgsLayoutItemShape(l)
|
||||
item1.attemptSetSceneRect(QRectF(10, 20, 100, 150))
|
||||
fill = QgsSimpleFillSymbolLayer()
|
||||
fill_symbol = QgsFillSymbol()
|
||||
fill_symbol.changeSymbolLayer(0, fill)
|
||||
fill.setColor(Qt.green)
|
||||
fill.setStrokeStyle(Qt.NoPen)
|
||||
item1.setSymbol(fill_symbol)
|
||||
l.addItem(item1)
|
||||
|
||||
item2 = QgsLayoutItemShape(l)
|
||||
item2.attemptSetSceneRect(QRectF(10, 20, 100, 150))
|
||||
item2.attemptMove(QgsLayoutPoint(10, 20), page=1)
|
||||
fill = QgsSimpleFillSymbolLayer()
|
||||
fill_symbol = QgsFillSymbol()
|
||||
fill_symbol.changeSymbolLayer(0, fill)
|
||||
fill.setColor(Qt.cyan)
|
||||
fill.setStrokeStyle(Qt.NoPen)
|
||||
item2.setSymbol(fill_symbol)
|
||||
l.addItem(item2)
|
||||
|
||||
exporter = QgsLayoutExporter(l)
|
||||
# setup settings
|
||||
settings = QgsLayoutExporter.PrintExportSettings()
|
||||
settings.dpi = 80
|
||||
settings.rasterizeWholeImage = False
|
||||
|
||||
pdf_file_path = os.path.join(self.basetestpath, 'test_printdpi.pdf')
|
||||
# make a qprinter directed to pdf
|
||||
printer = QPrinter()
|
||||
printer.setOutputFileName(pdf_file_path)
|
||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||
|
||||
self.assertEqual(exporter.print(printer, settings), QgsLayoutExporter.Success)
|
||||
self.assertTrue(os.path.exists(pdf_file_path))
|
||||
|
||||
rendered_page_1 = os.path.join(self.basetestpath, 'test_exporttopdfdpi.png')
|
||||
dpi = 80
|
||||
pdfToPng(pdf_file_path, rendered_page_1, dpi=dpi, page=1)
|
||||
rendered_page_2 = os.path.join(self.basetestpath, 'test_exporttopdfdpi2.png')
|
||||
pdfToPng(pdf_file_path, rendered_page_2, dpi=dpi, page=2)
|
||||
|
||||
self.assertTrue(self.checkImage('printdpi_page1', 'exporttopdfdpi_page1', rendered_page_1, size_tolerance=1))
|
||||
self.assertTrue(self.checkImage('printdpi_page2', 'exporttopdfdpi_page2', rendered_page_2, size_tolerance=1))
|
||||
|
||||
def testExportWorldFile(self):
|
||||
l = QgsLayout(QgsProject.instance())
|
||||
l.initializeDefaults()
|
||||
@ -727,6 +783,39 @@ class TestQgsLayoutExporter(unittest.TestCase):
|
||||
pdfToPng(pdf_path, rendered_page_4, dpi=80, page=4)
|
||||
self.assertTrue(os.path.exists(rendered_page_4))
|
||||
|
||||
def testPrintIterator(self):
|
||||
project, layout = self.prepareIteratorLayout()
|
||||
atlas = layout.atlas()
|
||||
|
||||
# setup settings
|
||||
settings = QgsLayoutExporter.PrintExportSettings()
|
||||
settings.dpi = 80
|
||||
settings.rasterizeWholeImage = False
|
||||
|
||||
pdf_path = os.path.join(self.basetestpath, 'test_printiterator.pdf')
|
||||
# make a qprinter directed to pdf
|
||||
printer = QPrinter()
|
||||
printer.setOutputFileName(pdf_path)
|
||||
printer.setOutputFormat(QPrinter.PdfFormat)
|
||||
|
||||
result, error = QgsLayoutExporter.print(atlas, printer, settings)
|
||||
self.assertEqual(result, QgsLayoutExporter.Success, error)
|
||||
|
||||
rendered_page_1 = os.path.join(self.basetestpath, 'test_printiterator1.png')
|
||||
pdfToPng(pdf_path, rendered_page_1, dpi=80, page=1)
|
||||
self.assertTrue(self.checkImage('printeriterator1', 'iteratortoimage1', rendered_page_1, size_tolerance=2))
|
||||
|
||||
rendered_page_2 = os.path.join(self.basetestpath, 'test_printiterator2.png')
|
||||
pdfToPng(pdf_path, rendered_page_2, dpi=80, page=2)
|
||||
self.assertTrue(self.checkImage('printiterator2', 'iteratortoimage2', rendered_page_2, size_tolerance=2))
|
||||
|
||||
rendered_page_3 = os.path.join(self.basetestpath, 'test_printiterator3.png')
|
||||
pdfToPng(pdf_path, rendered_page_3, dpi=80, page=3)
|
||||
self.assertTrue(os.path.exists(rendered_page_3))
|
||||
rendered_page_4 = os.path.join(self.basetestpath, 'test_printiterator4.png')
|
||||
pdfToPng(pdf_path, rendered_page_4, dpi=80, page=4)
|
||||
self.assertTrue(os.path.exists(rendered_page_4))
|
||||
|
||||
def testExportReport(self):
|
||||
p = QgsProject()
|
||||
r = QgsReport(p)
|
||||
|
Loading…
x
Reference in New Issue
Block a user