Skip to content

Commit cdf5cf2

Browse files
committed
Add report section subclass with single layout as body
1 parent acb4464 commit cdf5cf2

4 files changed

Lines changed: 142 additions & 44 deletions

File tree

python/core/layout/qgsabstractreportsection.sip

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ Subclasses should call copyCommonProperties() in their clone()
3838
implementations.
3939
%End
4040

41+
virtual int count();
42+
43+
virtual QString filePath( const QString &baseFilePath, const QString &extension );
44+
45+
46+
4147

4248
virtual QgsLayout *layout();
4349

@@ -225,13 +231,50 @@ This method should be called from clone() implementations.
225231
QgsAbstractReportSection( const QgsAbstractReportSection &other );
226232
};
227233

234+
class QgsReportSectionLayout : QgsAbstractReportSection
235+
{
236+
%Docstring
237+
A report section consisting of a single QgsLayout body.
238+
239+
.. versionadded:: 3.0
240+
%End
241+
242+
%TypeHeaderCode
243+
#include "qgsabstractreportsection.h"
244+
%End
245+
public:
246+
247+
QgsLayout *body();
248+
%Docstring
249+
Returns the body layout for the section.
250+
251+
.. seealso:: :py:func:`setBody()`
252+
%End
253+
254+
void setBody( QgsLayout *body /Transfer/ );
255+
%Docstring
256+
Sets the ``body`` layout for the section. Ownership of ``body``
257+
is transferred to the report section.
258+
259+
.. seealso:: :py:func:`body()`
260+
%End
261+
262+
virtual QgsReportSectionLayout *clone() const /Factory/;
263+
264+
virtual bool beginRender();
265+
266+
virtual bool next();
267+
268+
269+
};
270+
228271

229272
class QgsReport : QgsAbstractReportSection
230273
{
231274
%Docstring
232275
Represents a report for use with the QgsLayout engine.
233276

234-
Reports consist of multiple sections, represented by QgsAbstractReportSection
277+
Reports consist of multiple sections, represented by :py:class:`QgsAbstractReportSection`
235278
subclasses.
236279

237280
.. versionadded:: 3.0
@@ -250,15 +293,6 @@ Constructor for QgsReport.
250293
virtual QgsReport *clone() const /Factory/;
251294

252295

253-
virtual int count();
254-
virtual bool beginRender();
255-
256-
virtual bool next();
257-
258-
259-
virtual QString filePath( const QString &baseFilePath, const QString &extension );
260-
261-
262296
};
263297

264298
/************************************************************************

src/core/layout/qgsabstractreportsection.cpp

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ QgsAbstractReportSection::~QgsAbstractReportSection()
2222
qDeleteAll( mChildren );
2323
}
2424

25+
QString QgsAbstractReportSection::filePath( const QString &baseFilePath, const QString &extension )
26+
{
27+
QString base = QDir( baseFilePath ).filePath( "report_" ) + QString::number( mSectionNumber );
28+
if ( !extension.startsWith( '.' ) )
29+
base += '.';
30+
base += extension;
31+
return base;
32+
}
33+
2534
QgsLayout *QgsAbstractReportSection::layout()
2635
{
2736
return mCurrentLayout;
@@ -33,6 +42,7 @@ bool QgsAbstractReportSection::beginRender()
3342
mCurrentLayout = nullptr;
3443
mNextChild = 0;
3544
mNextSection = Header;
45+
mSectionNumber = 0;
3646

3747
// and all children too
3848
bool result = true;
@@ -45,6 +55,8 @@ bool QgsAbstractReportSection::beginRender()
4555

4656
bool QgsAbstractReportSection::next()
4757
{
58+
mSectionNumber++;
59+
4860
switch ( mNextSection )
4961
{
5062
case Header:
@@ -192,24 +204,38 @@ QgsReport *QgsReport::clone() const
192204
return copy.release();
193205
}
194206

195-
bool QgsReport::beginRender()
207+
//
208+
// QgsReportSectionLayout
209+
//
210+
211+
QgsReportSectionLayout *QgsReportSectionLayout::clone() const
196212
{
197-
mSectionNumber = 0;
198-
return QgsAbstractReportSection::beginRender();
213+
std::unique_ptr< QgsReportSectionLayout > copy = qgis::make_unique< QgsReportSectionLayout >();
214+
copyCommonProperties( copy.get() );
215+
216+
if ( mBody )
217+
copy->mBody.reset( mBody->clone() );
218+
else
219+
copy->mBody.reset();
220+
221+
return copy.release();
199222
}
200223

201-
bool QgsReport::next()
224+
bool QgsReportSectionLayout::beginRender()
202225
{
203-
mSectionNumber++;
204-
return QgsAbstractReportSection::next();
226+
mExportedBody = false;
227+
return QgsAbstractReportSection::beginRender();
205228
}
206229

207-
QString QgsReport::filePath( const QString &baseFilePath, const QString &extension )
230+
bool QgsReportSectionLayout::next()
208231
{
209-
QString base = QDir( baseFilePath ).filePath( "report_" ) + QString::number( mSectionNumber );
210-
if ( !extension.startsWith( '.' ) )
211-
base += '.';
212-
base += extension;
213-
return base;
214-
232+
if ( !mExportedBody )
233+
{
234+
mExportedBody = true;
235+
return true;
236+
}
237+
else
238+
{
239+
return false;
240+
}
215241
}

src/core/layout/qgsabstractreportsection.h

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
5151
*/
5252
virtual QgsAbstractReportSection *clone() const = 0 SIP_FACTORY;
5353

54+
// TODO - how to handle this?
55+
int count() override { return -1; }
56+
57+
//TODO - baseFilePath should be a filename, not directory
58+
QString filePath( const QString &baseFilePath, const QString &extension ) override;
59+
60+
5461
#if 0 //TODO
5562
virtual void setContext( const QgsLayoutReportContext &context ) = 0;
5663
#endif
@@ -199,6 +206,7 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
199206

200207
private:
201208

209+
int mSectionNumber = 0;
202210
SubSection mNextSection = Header;
203211
int mNextChild = 0;
204212
QgsLayout *mCurrentLayout = nullptr;
@@ -215,6 +223,40 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
215223
#endif
216224
};
217225

226+
/**
227+
* \ingroup core
228+
* \class QgsReportSectionLayout
229+
* \brief A report section consisting of a single QgsLayout body.
230+
* \since QGIS 3.0
231+
*/
232+
class CORE_EXPORT QgsReportSectionLayout : public QgsAbstractReportSection
233+
{
234+
public:
235+
236+
/**
237+
* Returns the body layout for the section.
238+
* \see setBody()
239+
*/
240+
QgsLayout *body() { return mBody.get(); }
241+
242+
/**
243+
* Sets the \a body layout for the section. Ownership of \a body
244+
* is transferred to the report section.
245+
* \see body()
246+
*/
247+
void setBody( QgsLayout *body SIP_TRANSFER ) { mBody.reset( body ); }
248+
249+
QgsReportSectionLayout *clone() const override SIP_FACTORY;
250+
bool beginRender() override;
251+
bool next() override;
252+
253+
private:
254+
255+
bool mExportedBody = false;
256+
std::unique_ptr< QgsLayout > mBody;
257+
258+
};
259+
218260

219261
/**
220262
* \ingroup core
@@ -236,18 +278,6 @@ class CORE_EXPORT QgsReport : public QgsAbstractReportSection
236278

237279
QgsReport *clone() const override SIP_FACTORY;
238280

239-
// TODO - how to handle this?
240-
int count() override { return -1; }
241-
bool beginRender() override;
242-
bool next() override;
243-
244-
//TODO - baseFilePath should be a filename, not directory
245-
QString filePath( const QString &baseFilePath, const QString &extension ) override;
246-
247-
private:
248-
249-
int mSectionNumber = 0;
250-
251281
};
252282

253283
#endif //QGSABSTRACTREPORTSECTION_H

tests/src/python/test_qgsreport.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616

1717
from qgis.core import (QgsProject,
1818
QgsLayout,
19-
QgsReport)
19+
QgsReport,
20+
QgsReportSectionLayout)
2021
from qgis.testing import start_app, unittest
2122

2223
start_app()
@@ -58,12 +59,12 @@ def testChildren(self):
5859
r.removeChild(None)
5960

6061
# append child
61-
child1 = QgsReport()
62+
child1 = QgsReportSectionLayout()
6263
r.appendChild(child1)
6364
self.assertEqual(r.childCount(), 1)
6465
self.assertEqual(r.children(), [child1])
6566
self.assertEqual(r.child(0), child1)
66-
child2 = QgsReport()
67+
child2 = QgsReportSectionLayout()
6768
r.appendChild(child2)
6869
self.assertEqual(r.childCount(), 2)
6970
self.assertEqual(r.children(), [child1, child2])
@@ -73,11 +74,11 @@ def testInsertChild(self):
7374
p = QgsProject()
7475
r = QgsReport()
7576

76-
child1 = QgsReport()
77+
child1 = QgsReportSectionLayout()
7778
r.insertChild(11, child1)
7879
self.assertEqual(r.childCount(), 1)
7980
self.assertEqual(r.children(), [child1])
80-
child2 = QgsReport()
81+
child2 = QgsReportSectionLayout()
8182
r.insertChild(-1, child2)
8283
self.assertEqual(r.childCount(), 2)
8384
self.assertEqual(r.children(), [child2, child1])
@@ -86,9 +87,9 @@ def testRemoveChild(self):
8687
p = QgsProject()
8788
r = QgsReport()
8889

89-
child1 = QgsReport()
90+
child1 = QgsReportSectionLayout()
9091
r.appendChild(child1)
91-
child2 = QgsReport()
92+
child2 = QgsReportSectionLayout()
9293
r.appendChild(child2)
9394

9495
r.removeChildAt(-1)
@@ -109,10 +110,10 @@ def testClone(self):
109110
p = QgsProject()
110111
r = QgsReport()
111112

112-
child1 = QgsReport()
113+
child1 = QgsReportSectionLayout()
113114
child1.setHeaderEnabled(True)
114115
r.appendChild(child1)
115-
child2 = QgsReport()
116+
child2 = QgsReportSectionLayout()
116117
child2.setFooterEnabled(True)
117118
r.appendChild(child2)
118119

@@ -123,6 +124,13 @@ def testClone(self):
123124
self.assertFalse(cloned.child(1).headerEnabled())
124125
self.assertTrue(cloned.child(1).footerEnabled())
125126

127+
def testReportSectionLayout(self):
128+
r = QgsReportSectionLayout()
129+
p = QgsProject()
130+
body = QgsLayout(p)
131+
r.setBody(body)
132+
self.assertEqual(r.body(), body)
133+
126134

127135
if __name__ == '__main__':
128136
unittest.main()

0 commit comments

Comments
 (0)