Skip to content

Commit

Permalink
[layouts] Nicer detection of rendering in a view
Browse files Browse the repository at this point in the history
In compositions, a flag must be explicitly set to indicate
whether the render occuring is for "previews" (i.e.
rendering in a graphics view) or outputs (i.e. rendering
to a image/pdf/other destination device)

This isn't nice api.

So we avoid this by checking the paint device type when
an item is being rendered.
  • Loading branch information
nyalldawson committed Nov 7, 2017
1 parent 625eef8 commit 9630a39
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 7 deletions.
8 changes: 8 additions & 0 deletions python/core/layout/qgslayoutitem.sip
Expand Up @@ -589,6 +589,14 @@ 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
35 changes: 29 additions & 6 deletions src/core/layout/qgslayoutitem.cpp
Expand Up @@ -224,7 +224,7 @@ void QgsLayoutItem::setParentGroup( QgsLayoutItemGroup *group )

void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
{
if ( !painter || !painter->device() || !shouldDrawItem() )
if ( !painter || !painter->device() || !shouldDrawItem( painter ) )
{
return;
}
Expand Down Expand Up @@ -431,15 +431,13 @@ bool QgsLayoutItem::shouldBlockUndoCommands() const
return !mLayout || mLayout != scene() || mBlockUndoCommands;
}

bool QgsLayoutItem::shouldDrawItem() const
bool QgsLayoutItem::shouldDrawItem( QPainter *painter ) const
{
#if 0 //TODO
if ( ( mLayout && mLayout->plotStyle() == QgsComposition::Preview ) || !mLayout )
if ( isPreviewRender( painter ) )
{
//preview mode or no composition, so OK to draw item
//preview mode so OK to draw item
return true;
}
#endif

//exporting layout, so check if item is excluded from exports
return !mEvaluatedExcludeFromExports;
Expand Down Expand Up @@ -769,6 +767,31 @@ 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
11 changes: 10 additions & 1 deletion src/core/layout/qgslayoutitem.h
Expand Up @@ -583,6 +583,13 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt
*/
virtual void drawBackground( QgsRenderContext &context );

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

/**
* Sets a fixed \a size for the layout item, which prevents it from being freely
* resized. Set an empty size if item can be freely resized.
Expand Down Expand Up @@ -770,10 +777,12 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt

/**
* Returns whether the item should be drawn in the current context
* and to the given \a painter.
*/
bool shouldDrawItem() const;
bool shouldDrawItem( QPainter *painter ) const;

friend class TestQgsLayoutItem;
friend class TestQgsLayoutView;
friend class QgsLayoutItemGroup;
};

Expand Down
87 changes: 87 additions & 0 deletions tests/src/gui/testqgslayoutview.cpp
Expand Up @@ -23,9 +23,12 @@
#include "qgslayoutitemregistry.h"
#include "qgslayoutitemguiregistry.h"
#include "qgslayoutitemwidget.h"
#include "qgslayoutitemshape.h"
#include "qgsproject.h"
#include "qgsgui.h"
#include <QtTest/QSignalSpy>
#include <QSvgGenerator>
#include <QPrinter>

class TestQgsLayoutView: public QObject
{
Expand All @@ -40,6 +43,7 @@ class TestQgsLayoutView: public QObject
void events();
void guiRegistry();
void rubberBand();
void isPreviewRender();

private:

Expand Down Expand Up @@ -320,5 +324,88 @@ void TestQgsLayoutView::rubberBand()
QCOMPARE( band.pen().color(), QColor( 0, 255, 0 ) );
}

class TestViewItem : public QgsLayoutItem
{
Q_OBJECT

public:

TestViewItem( QgsLayout *layout ) : QgsLayoutItem( layout )
{
}

//implement pure virtual methods
int type() const override { return QgsLayoutItemRegistry::LayoutItem + 101; }
QString stringType() const override { return QStringLiteral( "TestItemType" ); }
bool mDrawn = false;
bool mPreview = false;

protected:
void paint( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget * ) override
{
mDrawn = true;
mPreview = isPreviewRender( painter );
}
void draw( QgsRenderContext &, const QStyleOptionGraphicsItem * ) override
{

}

};

void TestQgsLayoutView::isPreviewRender()
{
// test if items can detect whether a preview render is occurring
QgsProject p;
QgsLayoutView *view = new QgsLayoutView();
QgsLayout *layout = new QgsLayout( &p );
view->setCurrentLayout( layout );

TestViewItem *item = new TestViewItem( layout );
layout->addLayoutItem( item );
item->attemptMove( QgsLayoutPoint( 0, 0 ) );
item->attemptResize( QgsLayoutSize( 100, 100 ) );
layout->updateBounds();


// render to image
QVERIFY( !item->isPreviewRender( nullptr ) );
QImage im = QImage( 250, 250, QImage::Format_RGB32 );
QPainter painter;
QVERIFY( painter.begin( &im ) );
QVERIFY( !item->isPreviewRender( &painter ) );
painter.end();

// render to svg
QSvgGenerator generator;
generator.setFileName( QDir::tempPath() + "/layout_text.svg" );
QVERIFY( painter.begin( &generator ) );
QVERIFY( !item->isPreviewRender( &painter ) );
painter.end();

// render to pdf
QPrinter printer;
printer.setOutputFileName( QString() );
printer.setOutputFormat( QPrinter::PdfFormat );
printer.setOutputFileName( QDir::tempPath() + "/layout_text.pdf" );
QVERIFY( painter.begin( &printer ) );
QVERIFY( !item->isPreviewRender( &painter ) );
painter.end();

// render in view - kinda gross!
item->mDrawn = false;
item->mPreview = false;
view->show();
view->zoomFull();
while ( !item->mDrawn )
{
QApplication::processEvents();
}

QVERIFY( item->mDrawn );
QVERIFY( item->mPreview );

}

QGSTEST_MAIN( TestQgsLayoutView )
#include "testqgslayoutview.moc"

0 comments on commit 9630a39

Please sign in to comment.