1 /***************************************************************************
2 testqgslayoutshapes.cpp
3 ----------------------
4 begin : October 2017
5 copyright : (C) 2017 by Nyall Dawson
6 email : nyall dot dawson at gmail.com
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "qgsapplication.h"
19 #include "qgslayout.h"
20 #include "qgsmultirenderchecker.h"
21 #include "qgslayoutitemshape.h"
22 #include "qgsmapsettings.h"
23 #include "qgsproject.h"
24 #include "qgssymbol.h"
25 #include "qgssinglesymbolrenderer.h"
26 #include "qgsfillsymbollayer.h"
27 #include "qgsreadwritecontext.h"
28 #include <QObject>
29 #include "qgstest.h"
30 #include <QColor>
31 #include <QPainter>
32
33 class TestQgsLayoutShapes : public QObject
34 {
35 Q_OBJECT
36
37 public:
38 TestQgsLayoutShapes() = default;
39
40 private slots:
41 void initTestCase();// will be called before the first testfunction is executed.
42 void cleanupTestCase();// will be called after the last testfunction was executed.
43 void init();// will be called before each testfunction is executed.
44 void cleanup();// will be called after every testfunction.
45 void rectangle(); //test if rectangle shape is functioning
46 void triangle(); //test if triangle shape is functioning
47 void ellipse(); //test if ellipse shape is functioning
48 void roundedRectangle(); //test if rounded rectangle shape is functioning
49 void symbol(); //test if styling shapes via symbol is working
50 void readWriteXml();
51 void bounds();
52 void shapeRotation();
53
54 private:
55
56 QString mReport;
57 };
58
initTestCase()59 void TestQgsLayoutShapes::initTestCase()
60 {
61 QgsApplication::init();
62 QgsApplication::initQgis();
63
64 mReport = QStringLiteral( "<h1>Composer Shape Tests</h1>\n" );
65 }
66
cleanupTestCase()67 void TestQgsLayoutShapes::cleanupTestCase()
68 {
69 QString myReportFile = QDir::tempPath() + "/qgistest.html";
70 QFile myFile( myReportFile );
71 if ( myFile.open( QIODevice::WriteOnly | QIODevice::Append ) )
72 {
73 QTextStream myQTextStream( &myFile );
74 myQTextStream << mReport;
75 myFile.close();
76 }
77 QgsApplication::exitQgis();
78 }
79
init()80 void TestQgsLayoutShapes::init()
81 {
82
83 }
84
cleanup()85 void TestQgsLayoutShapes::cleanup()
86 {
87
88 }
89
rectangle()90 void TestQgsLayoutShapes::rectangle()
91 {
92 QgsProject p;
93 QgsLayout l( &p );
94 l.initializeDefaults();
95
96 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
97 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
98 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
99
100
101 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
102 std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
103 fillSymbol->changeSymbolLayer( 0, simpleFill );
104 simpleFill->setColor( QColor( 255, 150, 0 ) );
105 simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
106 simpleFill->setStrokeWidth( 0.3 );
107 simpleFill->setPenJoinStyle( Qt::MiterJoin );
108 shape->setSymbol( fillSymbol.get() );
109
110 l.addLayoutItem( shape );
111
112 QgsLayoutChecker checker( QStringLiteral( "composershapes_rectangle" ), &l );
113 checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
114 QVERIFY( checker.testLayout( mReport ) );
115 }
116
triangle()117 void TestQgsLayoutShapes::triangle()
118 {
119 QgsProject p;
120 QgsLayout l( &p );
121 l.initializeDefaults();
122
123 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
124 shape->setShapeType( QgsLayoutItemShape::Triangle );
125 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
126 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
127
128
129 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
130 std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
131 fillSymbol->changeSymbolLayer( 0, simpleFill );
132 simpleFill->setColor( QColor( 255, 150, 0 ) );
133 simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
134 simpleFill->setStrokeWidth( 0.3 );
135 simpleFill->setPenJoinStyle( Qt::MiterJoin );
136 shape->setSymbol( fillSymbol.get() );
137
138 l.addLayoutItem( shape );
139
140 QgsLayoutChecker checker( QStringLiteral( "composershapes_triangle" ), &l );
141 checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
142 QVERIFY( checker.testLayout( mReport ) );
143 }
144
ellipse()145 void TestQgsLayoutShapes::ellipse()
146 {
147 QgsProject p;
148 QgsLayout l( &p );
149 l.initializeDefaults();
150
151 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
152 shape->setShapeType( QgsLayoutItemShape::Ellipse );
153 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
154 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
155
156 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
157 std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
158 fillSymbol->changeSymbolLayer( 0, simpleFill );
159 simpleFill->setColor( QColor( 255, 150, 0 ) );
160 simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
161 simpleFill->setStrokeWidth( 0.3 );
162 simpleFill->setPenJoinStyle( Qt::MiterJoin );
163 shape->setSymbol( fillSymbol.get() );
164
165 l.addLayoutItem( shape );
166
167 QgsLayoutChecker checker( QStringLiteral( "composershapes_ellipse" ), &l );
168 checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
169 QVERIFY( checker.testLayout( mReport ) );
170 }
171
roundedRectangle()172 void TestQgsLayoutShapes::roundedRectangle()
173 {
174 QgsProject p;
175 QgsLayout l( &p );
176 l.initializeDefaults();
177
178 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
179 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
180 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
181
182 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
183 std::unique_ptr< QgsFillSymbol > fillSymbol( new QgsFillSymbol() );
184 fillSymbol->changeSymbolLayer( 0, simpleFill );
185 simpleFill->setColor( QColor( 255, 150, 0 ) );
186 simpleFill->setStrokeColor( QColor( 0, 0, 0 ) );
187 simpleFill->setStrokeWidth( 0.3 );
188 simpleFill->setPenJoinStyle( Qt::MiterJoin );
189 shape->setSymbol( fillSymbol.get() );
190
191 l.addLayoutItem( shape );
192
193 shape->setCornerRadius( QgsLayoutMeasurement( 30 ) );
194
195 QgsLayoutChecker checker( QStringLiteral( "composershapes_roundedrect" ), &l );
196 checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
197 QVERIFY( checker.testLayout( mReport ) );
198 }
199
symbol()200 void TestQgsLayoutShapes::symbol()
201 {
202 QgsProject p;
203 QgsLayout l( &p );
204 l.initializeDefaults();
205
206 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
207 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
208 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
209
210 //setup simple fill
211 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
212 QgsFillSymbol *fillSymbol = new QgsFillSymbol();
213 fillSymbol->changeSymbolLayer( 0, simpleFill );
214 simpleFill->setColor( Qt::green );
215 simpleFill->setStrokeColor( Qt::yellow );
216 simpleFill->setStrokeWidth( 6 );
217 shape->setSymbol( fillSymbol );
218 delete fillSymbol;
219
220 l.addLayoutItem( shape );
221 QgsLayoutChecker checker( QStringLiteral( "composershapes_symbol" ), &l );
222 checker.setControlPathPrefix( QStringLiteral( "composer_shapes" ) );
223 QVERIFY( checker.testLayout( mReport ) );
224 }
225
readWriteXml()226 void TestQgsLayoutShapes::readWriteXml()
227 {
228 QgsProject p;
229 QgsLayout l( &p );
230 std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( &l );
231 shape->setShapeType( QgsLayoutItemShape::Triangle );
232 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
233 QgsFillSymbol *fillSymbol = new QgsFillSymbol();
234 fillSymbol->changeSymbolLayer( 0, simpleFill );
235 simpleFill->setColor( Qt::green );
236 simpleFill->setStrokeColor( Qt::yellow );
237 simpleFill->setStrokeWidth( 6 );
238 shape->setSymbol( fillSymbol );
239 delete fillSymbol;
240
241 //save original item to xml
242 QDomImplementation DomImplementation;
243 QDomDocumentType documentType =
244 DomImplementation.createDocumentType(
245 QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
246 QDomDocument doc( documentType );
247 QDomElement rootNode = doc.createElement( QStringLiteral( "qgis" ) );
248
249 shape->writeXml( rootNode, doc, QgsReadWriteContext() );
250
251 //create new item and restore settings from xml
252 std::unique_ptr< QgsLayoutItemShape > copy = qgis::make_unique< QgsLayoutItemShape >( &l );
253 QVERIFY( copy->readXml( rootNode.firstChildElement(), doc, QgsReadWriteContext() ) );
254 QCOMPARE( copy->shapeType(), QgsLayoutItemShape::Triangle );
255 QCOMPARE( copy->symbol()->symbolLayer( 0 )->color().name(), QStringLiteral( "#00ff00" ) );
256 QCOMPARE( copy->symbol()->symbolLayer( 0 )->strokeColor().name(), QStringLiteral( "#ffff00" ) );
257 }
258
bounds()259 void TestQgsLayoutShapes::bounds()
260 {
261 QgsProject p;
262 QgsLayout l( &p );
263 std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( &l );
264 shape->attemptMove( QgsLayoutPoint( 20, 20 ) );
265 shape->attemptResize( QgsLayoutSize( 150, 100 ) );
266
267 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
268 QgsFillSymbol *fillSymbol = new QgsFillSymbol();
269 fillSymbol->changeSymbolLayer( 0, simpleFill );
270 simpleFill->setColor( Qt::green );
271 simpleFill->setStrokeColor( Qt::yellow );
272 simpleFill->setStrokeWidth( 6 );
273 shape->setSymbol( fillSymbol );
274 delete fillSymbol;
275
276 // scene bounding rect should include symbol outline
277 QRectF bounds = shape->sceneBoundingRect();
278 QCOMPARE( bounds.left(), 17.0 );
279 QCOMPARE( bounds.right(), 173.0 );
280 QCOMPARE( bounds.top(), 17.0 );
281 QCOMPARE( bounds.bottom(), 123.0 );
282
283 // rectWithFrame should include symbol outline too
284 bounds = shape->rectWithFrame();
285 QCOMPARE( bounds.left(), -3.0 );
286 QCOMPARE( bounds.right(), 153.0 );
287 QCOMPARE( bounds.top(), -3.0 );
288 QCOMPARE( bounds.bottom(), 103.0 );
289 }
290
shapeRotation()291 void TestQgsLayoutShapes::shapeRotation()
292 {
293 QgsProject p;
294 QgsLayout l( &p );
295 l.initializeDefaults();
296
297 QgsLayoutItemShape *shape = new QgsLayoutItemShape( &l );
298 shape->attemptSetSceneRect( QRectF( 70, 70, 150, 100 ) );
299 shape->setItemRotation( 45 );
300
301 //setup simple fill
302 QgsSimpleFillSymbolLayer *simpleFill = new QgsSimpleFillSymbolLayer();
303 QgsFillSymbol *fillSymbol = new QgsFillSymbol();
304 fillSymbol->changeSymbolLayer( 0, simpleFill );
305 simpleFill->setColor( QColor( 255, 150, 0 ) );
306 simpleFill->setStrokeColor( Qt::black );
307 //simpleFill->setStrokeColor( Qt::yellow );
308 //simpleFill->setStrokeWidth( 6 );
309 shape->setSymbol( fillSymbol );
310 delete fillSymbol;
311
312 l.addLayoutItem( shape );
313 QgsLayoutChecker checker( QStringLiteral( "composerrotation_shape" ), &l );
314 checker.setControlPathPrefix( QStringLiteral( "composer_items" ) );
315 QVERIFY( checker.testLayout( mReport ) );
316 }
317
318 QGSTEST_MAIN( TestQgsLayoutShapes )
319 #include "testqgslayoutshapes.moc"
320