Skip to content
Permalink
Browse files

More shape porting

  • Loading branch information
nyalldawson committed Oct 16, 2017
1 parent cf7714b commit f524c80b11f75cdb7d38d44a6a539c6a1945d6af
@@ -34,6 +34,9 @@ class QgsLayoutItemShape : QgsLayoutItem
:rtype: QgsFillSymbol
%End

virtual QRectF boundingRect() const;


protected:

explicit QgsLayoutItemShape( QgsLayout *layout );
@@ -17,6 +17,7 @@
#include "qgslayoutitemshape.h"
#include "qgslayout.h"
#include "qgslayoututils.h"
#include "qgssymbollayerutils.h"

#include <QPainter>

@@ -33,6 +34,38 @@ QgsLayoutItemShape::QgsLayoutItemShape( QgsLayout *layout )
properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) );
properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) );
mShapeStyleSymbol.reset( QgsFillSymbol::createSimple( properties ) );
refreshSymbol();

connect( this, &QgsLayoutItemShape::sizePositionChanged, this, [ = ]
{
updateBoundingRect();
update();
} );
}

void QgsLayoutItemShape::refreshSymbol()
{
if ( layout() )
{
QgsRenderContext rc = QgsLayoutUtils::createRenderContextForLayout( layout(), nullptr, layout()->context().dpi() );
mMaxSymbolBleed = ( 25.4 / layout()->context().dpi() ) * QgsSymbolLayerUtils::estimateMaxSymbolBleed( mShapeStyleSymbol.get(), rc );
}

updateBoundingRect();

update();
emit frameChanged();
}

void QgsLayoutItemShape::updateBoundingRect()
{
QRectF rectangle = rect();
rectangle.adjust( -mMaxSymbolBleed, -mMaxSymbolBleed, mMaxSymbolBleed, mMaxSymbolBleed );
if ( rectangle != mCurrentRectangle )
{
prepareGeometryChange();
mCurrentRectangle = rectangle;
}
}

void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
@@ -41,6 +74,12 @@ void QgsLayoutItemShape::setSymbol( QgsFillSymbol *symbol )
return;

mShapeStyleSymbol.reset( symbol->clone() );
refreshSymbol();
}

QRectF QgsLayoutItemShape::boundingRect() const
{
return mCurrentRectangle;
}

//
@@ -48,15 +48,35 @@ class CORE_EXPORT QgsLayoutItemShape : public QgsLayoutItem
*/
QgsFillSymbol *symbol() { return mShapeStyleSymbol.get(); }

// Depending on the symbol style, the bounding rectangle can be larger than the shape
QRectF boundingRect() const override;

protected:

/**
* Constructor for QgsLayoutItemShape, with the specified parent \a layout.
*/
explicit QgsLayoutItemShape( QgsLayout *layout );

private slots:

/**
* Should be called after the shape's symbol is changed. Redraws the shape and recalculates
* its selection bounds.
*/
void refreshSymbol();

//! Updates the bounding rect of this item
void updateBoundingRect();

private:
std::unique_ptr< QgsFillSymbol > mShapeStyleSymbol;

double mMaxSymbolBleed = 0.0;
//! Current bounding rectangle of shape
QRectF mCurrentRectangle;


};


@@ -138,6 +138,7 @@ SET(TESTS
testqgslayoutmodel.cpp
testqgslayoutobject.cpp
testqgslayoutpage.cpp
testqgslayoutshapes.cpp
testqgslayoutunits.cpp
testqgslayoututils.cpp
testqgslegendrenderer.cpp
@@ -0,0 +1,221 @@
/***************************************************************************
testqgslayoutshapes.cpp
----------------------
begin : October 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail.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 "qgsapplication.h"
#include "qgslayout.h"
#include "qgsmultirenderchecker.h"
#include "qgslayoutitemshape.h"
#include "qgsmapsettings.h"
#include "qgsproject.h"
#include "qgssymbol.h"
#include "qgssinglesymbolrenderer.h"
#include "qgsfillsymbollayer.h"
#include <QObject>
#include "qgstest.h"
#include <QColor>
#include <QPainter>

class TestQgsLayoutShapes : public QObject
{
Q_OBJECT

public:
TestQgsLayoutShapes() = default;

private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void rectangle(); //test if rectangle shape is functioning
void triangle(); //test if triange shape is functioning
void ellipse(); //test if ellipse shape is functioning
void roundedRectangle(); //test if rounded rectangle shape is functioning
void symbol(); //test is styling shapes via symbol is working

private:

QString mReport;
};

void TestQgsLayoutShapes::initTestCase()
{
QgsApplication::init();
QgsApplication::initQgis();

mReport = QStringLiteral( "<h1>Composer Shape Tests</h1>\n" );
}

void TestQgsLayoutShapes::cleanupTestCase()
{
QString myReportFile = QDir::tempPath() + "/qgistest.html";
QFile myFile( myReportFile );
if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
{
QTextStream myQTextStream( &myFile );
myQTextStream << mReport;
myFile.close();
}
QgsApplication::exitQgis();
}

void TestQgsLayoutShapes::init()
{

}

void TestQgsLayoutShapes::cleanup()
{

}

void TestQgsLayoutShapes::rectangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );


QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_rectangle" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::triangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemTriangleShape *shape = new QgsLayoutItemTriangleShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );


QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_triangle" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::ellipse()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemEllipseShape *shape = new QgsLayoutItemEllipseShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

QgsLayoutChecker checker( QStringLiteral( "composershapes_ellipse" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::roundedRectangle()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( QColor( 255, 150, 0 ) );
simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
simpleFill->setStrokeWidth( 0.3 );
simpleFill->setPenJoinStyle( Qt::MiterJoin );
shape->setSymbol( fillSymbol.get() );

l.addLayoutItem( shape );

shape->setCornerRadius( QgsLayoutMeasurement( 30 ) );

QgsLayoutChecker checker( QStringLiteral( "composershapes_roundedrect" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

void TestQgsLayoutShapes::symbol()
{
QgsProject p;
QgsLayout l( &p );
l.initializeDefaults();

QgsLayoutItemRectangularShape *shape = new QgsLayoutItemRectangularShape( &l );
shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
shape->attemptResize( QgsLayoutSize( 150, 100 ) );

//setup simple fill
QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
QgsFillSymbol *fillSymbol = new QgsFillSymbol();
fillSymbol->changeSymbolLayer( 0, simpleFill );
simpleFill->setColor( Qt::green );
simpleFill->setStrokeColor( Qt::yellow );
simpleFill->setStrokeWidth( 6 );
shape->setSymbol( fillSymbol );
delete fillSymbol;

l.addLayoutItem( shape );
QgsLayoutChecker checker( QStringLiteral( "composershapes_symbol" ), &l );
checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
QVERIFY( checker.testLayout( mReport ) );
}

QGSTEST_MAIN( TestQgsLayoutShapes )
#include "testqgslayoutshapes.moc"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

0 comments on commit f524c80

Please sign in to comment.
You can’t perform that action at this time.