Skip to content

Commit

Permalink
Start work on exporter for layouts
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Nov 7, 2017
1 parent 9630a39 commit edecc37
Show file tree
Hide file tree
Showing 20 changed files with 412 additions and 54 deletions.
1 change: 1 addition & 0 deletions python/core/core_auto.sip
Expand Up @@ -158,6 +158,7 @@
%Include composer/qgscomposertexttable.sip
%Include composer/qgspaperitem.sip
%Include layout/qgslayoutaligner.sip
%Include layout/qgslayoutexporter.sip
%Include layout/qgslayoutgridsettings.sip
%Include layout/qgslayoutmeasurement.sip
%Include layout/qgslayoutmeasurementconverter.sip
Expand Down
7 changes: 7 additions & 0 deletions python/core/layout/qgslayout.sip
Expand Up @@ -62,6 +62,13 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
:rtype: QgsLayoutModel
%End

QgsLayoutExporter &exporter();
%Docstring
Returns the layout's exporter, which is used for rendering the layout and exporting
to various formats.
:rtype: QgsLayoutExporter
%End

QString name() const;
%Docstring
Returns the layout's name.
Expand Down
57 changes: 57 additions & 0 deletions python/core/layout/qgslayoutexporter.sip
@@ -0,0 +1,57 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutexporter.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/



class QgsLayoutExporter
{
%Docstring
Handles rendering and exports of layouts to various formats.
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgslayoutexporter.h"
%End
public:

QgsLayoutExporter( QgsLayout *layout );
%Docstring
Constructor for QgsLayoutExporter, for the specified ``layout``.
%End

void renderPage( QPainter *painter, int page );
%Docstring
Renders a full page to a destination ``painter``.

The ``page`` argument specifies the page number to render. Page numbers
are 0 based, such that the first page in a layout is page 0.

.. seealso:: renderRect()
%End

void renderRegion( QPainter *painter, const QRectF &region );
%Docstring
Renders a ``region`` from the layout to a ``painter``. This method can be used
to render sections of pages rather than full pages.

.. seealso:: renderPage()
%End

};




/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutexporter.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
8 changes: 0 additions & 8 deletions python/core/layout/qgslayoutitem.sip
Expand Up @@ -589,14 +589,6 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt
Draws the background for the item.
%End

bool isPreviewRender( QPainter *painter ) const;
%Docstring
Returns true if the render to the specified ``painter`` is a preview render,
i.e. is being rendered inside a QGraphicsView widget as opposed to a destination
device (such as an image).
:rtype: bool
%End

virtual void setFixedSize( const QgsLayoutSize &size );
%Docstring
Sets a fixed ``size`` for the layout item, which prevents it from being freely
Expand Down
9 changes: 9 additions & 0 deletions python/core/layout/qgslayoututils.sip
Expand Up @@ -72,6 +72,15 @@ class QgsLayoutUtils
:rtype: float
%End


static bool isPreviewRender( QPainter *painter );
%Docstring
Returns true if the render to the specified ``painter`` is a preview render,
i.e. is being rendered inside a QGraphicsView widget as opposed to a destination
device (such as an image).
:rtype: bool
%End

};

/************************************************************************
Expand Down
38 changes: 38 additions & 0 deletions python/core/qgsmultirenderchecker.sip
Expand Up @@ -152,6 +152,44 @@ class QgsCompositionChecker : QgsMultiRenderChecker

};

class QgsLayoutChecker : QgsMultiRenderChecker
{
%Docstring
Renders a layout to an image and compares with an expected output
.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsmultirenderchecker.h"
%End
public:

QgsLayoutChecker( const QString &testName, QgsLayout *layout );
%Docstring
Constructor for QgsLayoutChecker.
%End

void setSize( QSize size );
%Docstring
Sets the output (reference) image ``size``.
%End

bool runTest( QString &report, int page = 0, int pixelDiff = 0 );
%Docstring
Runs a render check on the layout, adding results to the specified ``report``.

The maximum number of allowable pixels differing from the reference image is
specified via the ``pixelDiff`` argument.

The page number is specified via ``page``, where 0 corresponds to the first
page in the layout.

Returns false if the rendered layout differs from the expected reference image.
:rtype: bool
%End

};

%End


Expand Down
2 changes: 2 additions & 0 deletions src/core/CMakeLists.txt
Expand Up @@ -363,6 +363,7 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutaligner.cpp
layout/qgslayoutcontext.cpp
layout/qgslayouteffect.cpp
layout/qgslayoutexporter.cpp
layout/qgslayoutgridsettings.cpp
layout/qgslayoutguidecollection.cpp
layout/qgslayoutitem.cpp
Expand Down Expand Up @@ -975,6 +976,7 @@ SET(QGIS_CORE_HDRS
composer/qgspaperitem.h

layout/qgslayoutaligner.h
layout/qgslayoutexporter.h
layout/qgslayoutgridsettings.h
layout/qgslayoutitemundocommand.h
layout/qgslayoutmeasurement.h
Expand Down
6 changes: 6 additions & 0 deletions src/core/layout/qgslayout.cpp
Expand Up @@ -31,6 +31,7 @@ QgsLayout::QgsLayout( QgsProject *project )
, mGridSettings( this )
, mPageCollection( new QgsLayoutPageCollection( this ) )
, mUndoStack( new QgsLayoutUndoStack( this ) )
, mExporter( QgsLayoutExporter( this ) )
{
// just to make sure - this should be the default, but maybe it'll change in some future Qt version...
setBackgroundBrush( Qt::NoBrush );
Expand Down Expand Up @@ -87,6 +88,11 @@ QgsLayoutModel *QgsLayout::itemsModel()
return mItemsModel.get();
}

QgsLayoutExporter &QgsLayout::exporter()
{
return mExporter;
}

QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedItems )
{
QList<QgsLayoutItem *> layoutItemList;
Expand Down
8 changes: 8 additions & 0 deletions src/core/layout/qgslayout.h
Expand Up @@ -25,6 +25,7 @@
#include "qgslayoutgridsettings.h"
#include "qgslayoutguidecollection.h"
#include "qgslayoutundostack.h"
#include "qgslayoutexporter.h"

class QgsLayoutItemMap;
class QgsLayoutModel;
Expand Down Expand Up @@ -83,6 +84,12 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
*/
QgsLayoutModel *itemsModel();

/**
* Returns the layout's exporter, which is used for rendering the layout and exporting
* to various formats.
*/
QgsLayoutExporter &exporter();

/**
* Returns the layout's name.
* \see setName()
Expand Down Expand Up @@ -517,6 +524,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext

std::unique_ptr< QgsLayoutPageCollection > mPageCollection;
std::unique_ptr< QgsLayoutUndoStack > mUndoStack;
QgsLayoutExporter mExporter;

bool mBlockUndoCommands = false;

Expand Down
64 changes: 64 additions & 0 deletions src/core/layout/qgslayoutexporter.cpp
@@ -0,0 +1,64 @@
/***************************************************************************
qgslayoutexporter.cpp
-------------------
begin : October 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 "qgslayoutexporter.h"
#include "qgslayout.h"

QgsLayoutExporter::QgsLayoutExporter( QgsLayout *layout )
: mLayout( layout )
{

}

void QgsLayoutExporter::renderPage( QPainter *painter, int page )
{
if ( !mLayout )
return;

if ( mLayout->pageCollection()->pageCount() <= page || page < 0 )
{
return;
}

QgsLayoutItemPage *pageItem = mLayout->pageCollection()->page( page );
if ( !pageItem )
{
return;
}

QRectF paperRect = QRectF( pageItem->pos().x(), pageItem->pos().y(), pageItem->rect().width(), pageItem->rect().height() );
renderRegion( painter, paperRect );
}

void QgsLayoutExporter::renderRegion( QPainter *painter, const QRectF &region )
{
QPaintDevice *paintDevice = painter->device();
if ( !paintDevice || !mLayout )
{
return;
}

#if 0 //TODO
setSnapLinesVisible( false );
#endif

mLayout->render( painter, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), region );

#if 0 // TODO
setSnapLinesVisible( true );
#endif
}

67 changes: 67 additions & 0 deletions src/core/layout/qgslayoutexporter.h
@@ -0,0 +1,67 @@
/***************************************************************************
qgslayoutexporter.h
-------------------
begin : October 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. *
* *
***************************************************************************/
#ifndef QGSLAYOUTEXPORTER_H
#define QGSLAYOUTEXPORTER_H

#include "qgis_core.h"
#include <QPointer>

class QgsLayout;
class QPainter;

/**
* \ingroup core
* \class QgsLayoutExporter
* \brief Handles rendering and exports of layouts to various formats.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutExporter
{

public:

/**
* Constructor for QgsLayoutExporter, for the specified \a layout.
*/
QgsLayoutExporter( QgsLayout *layout );

/**
* Renders a full page to a destination \a painter.
*
* The \a page argument specifies the page number to render. Page numbers
* are 0 based, such that the first page in a layout is page 0.
*
* \see renderRect()
*/
void renderPage( QPainter *painter, int page );

/**
* Renders a \a region from the layout to a \a painter. This method can be used
* to render sections of pages rather than full pages.
*
* \see renderPage()
*/
void renderRegion( QPainter *painter, const QRectF &region );

private:

QPointer< QgsLayout > mLayout;
};

#endif //QGSLAYOUTEXPORTER_H



27 changes: 1 addition & 26 deletions src/core/layout/qgslayoutitem.cpp
Expand Up @@ -433,7 +433,7 @@ bool QgsLayoutItem::shouldBlockUndoCommands() const

bool QgsLayoutItem::shouldDrawItem( QPainter *painter ) const
{
if ( isPreviewRender( painter ) )
if ( QgsLayoutUtils::isPreviewRender( painter ) )
{
//preview mode so OK to draw item
return true;
Expand Down Expand Up @@ -767,31 +767,6 @@ void QgsLayoutItem::drawBackground( QgsRenderContext &context )
p->restore();
}

bool QgsLayoutItem::isPreviewRender( QPainter *painter ) const
{
if ( !painter || !painter->device() )
return false;

// if rendering to a QGraphicsView, we are in preview mode
QPaintDevice *device = painter->device();
if ( dynamic_cast< QPixmap * >( device ) )
return true;

QObject *obj = dynamic_cast< QObject *>( device );
if ( !obj )
return false;

const QMetaObject *mo = obj->metaObject();
while ( mo )
{
if ( mo->className() == QStringLiteral( "QGraphicsView" ) )
return true;

mo = mo->superClass();
}
return false;
}

void QgsLayoutItem::setFixedSize( const QgsLayoutSize &size )
{
mFixedSize = size;
Expand Down

0 comments on commit edecc37

Please sign in to comment.