Correct project and parent handling for report sections

This commit is contained in:
Nyall Dawson 2017-12-29 13:12:18 +10:00
parent 57628faa01
commit 6284f5e36f
5 changed files with 131 additions and 18 deletions

View File

@ -20,9 +20,10 @@ class QgsAbstractReportSection : QgsAbstractLayoutIterator
%End %End
public: public:
QgsAbstractReportSection(); QgsAbstractReportSection( QgsAbstractReportSection *parent = 0 );
%Docstring %Docstring
Constructor for QgsAbstractReportSection Constructor for QgsAbstractReportSection, attached to the specified ``parent`` section.
Note that ownership is not transferred to ``parent``.
%End %End
~QgsAbstractReportSection(); ~QgsAbstractReportSection();
@ -36,6 +37,16 @@ transferred to the caller.
Subclasses should call copyCommonProperties() in their clone() Subclasses should call copyCommonProperties() in their clone()
implementations. implementations.
%End
QgsAbstractReportSection *parent();
%Docstring
Returns the parent report section.
%End
QgsProject *project();
%Docstring
Returns the associated project.
%End %End
virtual int count(); virtual int count();
@ -230,6 +241,11 @@ Removes the child section at the specified ``index``, deleting it.
%Docstring %Docstring
Copies the common properties of a report section to a ``destination`` section. Copies the common properties of a report section to a ``destination`` section.
This method should be called from clone() implementations. This method should be called from clone() implementations.
%End
void setParent( QgsAbstractReportSection *parent );
%Docstring
Sets the ``parent`` report section.
%End %End
private: private:
@ -249,6 +265,12 @@ class QgsReportSectionLayout : QgsAbstractReportSection
%End %End
public: public:
QgsReportSectionLayout( QgsAbstractReportSection *parent = 0 );
%Docstring
Constructor for QgsReportSectionLayout, attached to the specified ``parent`` section.
Note that ownership is not transferred to ``parent``.
%End
QgsLayout *body(); QgsLayout *body();
%Docstring %Docstring
Returns the body layout for the section. Returns the body layout for the section.
@ -290,9 +312,17 @@ subclasses.
%End %End
public: public:
QgsReport(); QgsReport( QgsProject *project );
%Docstring %Docstring
Constructor for QgsReport. Constructor for QgsReport, associated with the specified
``project``.
Note that ownership is not transferred to ``project``.
%End
QgsProject *project();
%Docstring
Returns the associated project.
%End %End
virtual QgsReport *clone() const /Factory/; virtual QgsReport *clone() const /Factory/;

View File

@ -17,11 +17,31 @@
#include "qgsabstractreportsection.h" #include "qgsabstractreportsection.h"
#include "qgslayout.h" #include "qgslayout.h"
QgsAbstractReportSection::QgsAbstractReportSection( QgsAbstractReportSection *parent )
: mParent( parent )
{}
QgsAbstractReportSection::~QgsAbstractReportSection() QgsAbstractReportSection::~QgsAbstractReportSection()
{ {
qDeleteAll( mChildren ); qDeleteAll( mChildren );
} }
QgsProject *QgsAbstractReportSection::project()
{
QgsAbstractReportSection *current = this;
while ( QgsAbstractReportSection *parent = current->parent() )
{
if ( !parent )
return nullptr;
if ( QgsReport *report = dynamic_cast< QgsReport * >( parent ) )
return report->project();
current = parent;
}
return nullptr;
}
QString QgsAbstractReportSection::filePath( const QString &baseFilePath, const QString &extension ) QString QgsAbstractReportSection::filePath( const QString &baseFilePath, const QString &extension )
{ {
QString base = QStringLiteral( "%1_%2" ).arg( baseFilePath ).arg( mSectionNumber, 4, 10, QChar( '0' ) ); QString base = QStringLiteral( "%1_%2" ).arg( baseFilePath ).arg( mSectionNumber, 4, 10, QChar( '0' ) );
@ -158,11 +178,13 @@ QgsAbstractReportSection *QgsAbstractReportSection::child( int index )
void QgsAbstractReportSection::appendChild( QgsAbstractReportSection *section ) void QgsAbstractReportSection::appendChild( QgsAbstractReportSection *section )
{ {
section->setParent( this );
mChildren.append( section ); mChildren.append( section );
} }
void QgsAbstractReportSection::insertChild( int index, QgsAbstractReportSection *section ) void QgsAbstractReportSection::insertChild( int index, QgsAbstractReportSection *section )
{ {
section->setParent( this );
index = std::max( 0, index ); index = std::max( 0, index );
index = std::min( index, mChildren.count() ); index = std::min( index, mChildren.count() );
mChildren.insert( index, section ); mChildren.insert( index, section );
@ -202,16 +224,21 @@ void QgsAbstractReportSection::copyCommonProperties( QgsAbstractReportSection *d
for ( QgsAbstractReportSection *child : qgis::as_const( mChildren ) ) for ( QgsAbstractReportSection *child : qgis::as_const( mChildren ) )
{ {
destination->mChildren.append( child->clone() ); destination->appendChild( child->clone() );
} }
} }
// QgsReport // QgsReport
QgsReport::QgsReport( QgsProject *project )
: QgsAbstractReportSection( nullptr )
, mProject( project )
{}
QgsReport *QgsReport::clone() const QgsReport *QgsReport::clone() const
{ {
std::unique_ptr< QgsReport > copy = qgis::make_unique< QgsReport >(); std::unique_ptr< QgsReport > copy = qgis::make_unique< QgsReport >( mProject );
copyCommonProperties( copy.get() ); copyCommonProperties( copy.get() );
return copy.release(); return copy.release();
} }
@ -220,13 +247,19 @@ QgsReport *QgsReport::clone() const
// QgsReportSectionLayout // QgsReportSectionLayout
// //
QgsReportSectionLayout::QgsReportSectionLayout( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{}
QgsReportSectionLayout *QgsReportSectionLayout::clone() const QgsReportSectionLayout *QgsReportSectionLayout::clone() const
{ {
std::unique_ptr< QgsReportSectionLayout > copy = qgis::make_unique< QgsReportSectionLayout >(); std::unique_ptr< QgsReportSectionLayout > copy = qgis::make_unique< QgsReportSectionLayout >( nullptr );
copyCommonProperties( copy.get() ); copyCommonProperties( copy.get() );
if ( mBody ) if ( mBody )
{
copy->mBody.reset( mBody->clone() ); copy->mBody.reset( mBody->clone() );
}
else else
copy->mBody.reset(); copy->mBody.reset();

View File

@ -31,8 +31,11 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
public: public:
//! Constructor for QgsAbstractReportSection /**
QgsAbstractReportSection() = default; * Constructor for QgsAbstractReportSection, attached to the specified \a parent section.
* Note that ownership is not transferred to \a parent.
*/
QgsAbstractReportSection( QgsAbstractReportSection *parent = nullptr );
~QgsAbstractReportSection() override; ~QgsAbstractReportSection() override;
@ -51,6 +54,16 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/ */
virtual QgsAbstractReportSection *clone() const = 0 SIP_FACTORY; virtual QgsAbstractReportSection *clone() const = 0 SIP_FACTORY;
/**
* Returns the parent report section.
*/
QgsAbstractReportSection *parent() { return mParent; }
/**
* Returns the associated project.
*/
QgsProject *project();
// TODO - how to handle this? // TODO - how to handle this?
int count() override { return -1; } int count() override { return -1; }
@ -208,8 +221,15 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/ */
void copyCommonProperties( QgsAbstractReportSection *destination ) const; void copyCommonProperties( QgsAbstractReportSection *destination ) const;
/**
* Sets the \a parent report section.
*/
void setParent( QgsAbstractReportSection *parent ) { mParent = parent; }
private: private:
QgsAbstractReportSection *mParent = nullptr;
int mSectionNumber = 0; int mSectionNumber = 0;
SubSection mNextSection = Header; SubSection mNextSection = Header;
int mNextChild = 0; int mNextChild = 0;
@ -237,6 +257,12 @@ class CORE_EXPORT QgsReportSectionLayout : public QgsAbstractReportSection
{ {
public: public:
/**
* Constructor for QgsReportSectionLayout, attached to the specified \a parent section.
* Note that ownership is not transferred to \a parent.
*/
QgsReportSectionLayout( QgsAbstractReportSection *parent = nullptr );
/** /**
* Returns the body layout for the section. * Returns the body layout for the section.
* \see setBody() * \see setBody()
@ -277,11 +303,25 @@ class CORE_EXPORT QgsReport : public QgsAbstractReportSection
public: public:
//! Constructor for QgsReport. /**
QgsReport() = default; * Constructor for QgsReport, associated with the specified
* \a project.
*
* Note that ownership is not transferred to \a project.
*/
QgsReport( QgsProject *project );
/**
* Returns the associated project.
*/
QgsProject *project() { return mProject; }
QgsReport *clone() const override SIP_FACTORY; QgsReport *clone() const override SIP_FACTORY;
private:
QgsProject *mProject = nullptr;
}; };
#endif //QGSABSTRACTREPORTSECTION_H #endif //QGSABSTRACTREPORTSECTION_H

View File

@ -729,7 +729,7 @@ class TestQgsLayoutExporter(unittest.TestCase):
def testExportReport(self): def testExportReport(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
# add a header # add a header
r.setHeaderEnabled(True) r.setHeaderEnabled(True)

View File

@ -27,7 +27,9 @@ class TestQgsReport(unittest.TestCase):
def testGettersSetters(self): def testGettersSetters(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
self.assertEqual(r.project(), p)
r.setHeaderEnabled(True) r.setHeaderEnabled(True)
self.assertTrue(r.headerEnabled()) self.assertTrue(r.headerEnabled())
@ -45,7 +47,7 @@ class TestQgsReport(unittest.TestCase):
def testChildren(self): def testChildren(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
self.assertEqual(r.childCount(), 0) self.assertEqual(r.childCount(), 0)
self.assertEqual(r.children(), []) self.assertEqual(r.children(), [])
self.assertIsNone(r.child(-1)) self.assertIsNone(r.child(-1))
@ -60,32 +62,38 @@ class TestQgsReport(unittest.TestCase):
# append child # append child
child1 = QgsReportSectionLayout() child1 = QgsReportSectionLayout()
self.assertIsNone(child1.project())
r.appendChild(child1) r.appendChild(child1)
self.assertEqual(r.childCount(), 1) self.assertEqual(r.childCount(), 1)
self.assertEqual(r.children(), [child1]) self.assertEqual(r.children(), [child1])
self.assertEqual(r.child(0), child1) self.assertEqual(r.child(0), child1)
self.assertEqual(child1.parent(), r)
self.assertEqual(child1.project(), p)
child2 = QgsReportSectionLayout() child2 = QgsReportSectionLayout()
r.appendChild(child2) r.appendChild(child2)
self.assertEqual(r.childCount(), 2) self.assertEqual(r.childCount(), 2)
self.assertEqual(r.children(), [child1, child2]) self.assertEqual(r.children(), [child1, child2])
self.assertEqual(r.child(1), child2) self.assertEqual(r.child(1), child2)
self.assertEqual(child2.parent(), r)
def testInsertChild(self): def testInsertChild(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
child1 = QgsReportSectionLayout() child1 = QgsReportSectionLayout()
r.insertChild(11, child1) r.insertChild(11, child1)
self.assertEqual(r.childCount(), 1) self.assertEqual(r.childCount(), 1)
self.assertEqual(r.children(), [child1]) self.assertEqual(r.children(), [child1])
self.assertEqual(child1.parent(), r)
child2 = QgsReportSectionLayout() child2 = QgsReportSectionLayout()
r.insertChild(-1, child2) r.insertChild(-1, child2)
self.assertEqual(r.childCount(), 2) self.assertEqual(r.childCount(), 2)
self.assertEqual(r.children(), [child2, child1]) self.assertEqual(r.children(), [child2, child1])
self.assertEqual(child2.parent(), r)
def testRemoveChild(self): def testRemoveChild(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
child1 = QgsReportSectionLayout() child1 = QgsReportSectionLayout()
r.appendChild(child1) r.appendChild(child1)
@ -108,7 +116,7 @@ class TestQgsReport(unittest.TestCase):
def testClone(self): def testClone(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
child1 = QgsReportSectionLayout() child1 = QgsReportSectionLayout()
child1.setHeaderEnabled(True) child1.setHeaderEnabled(True)
@ -121,8 +129,10 @@ class TestQgsReport(unittest.TestCase):
self.assertEqual(cloned.childCount(), 2) self.assertEqual(cloned.childCount(), 2)
self.assertTrue(cloned.child(0).headerEnabled()) self.assertTrue(cloned.child(0).headerEnabled())
self.assertFalse(cloned.child(0).footerEnabled()) self.assertFalse(cloned.child(0).footerEnabled())
self.assertEqual(cloned.child(0).parent(), cloned)
self.assertFalse(cloned.child(1).headerEnabled()) self.assertFalse(cloned.child(1).headerEnabled())
self.assertTrue(cloned.child(1).footerEnabled()) self.assertTrue(cloned.child(1).footerEnabled())
self.assertEqual(cloned.child(1).parent(), cloned)
def testReportSectionLayout(self): def testReportSectionLayout(self):
r = QgsReportSectionLayout() r = QgsReportSectionLayout()
@ -133,7 +143,7 @@ class TestQgsReport(unittest.TestCase):
def testIteration(self): def testIteration(self):
p = QgsProject() p = QgsProject()
r = QgsReport() r = QgsReport(p)
# empty report # empty report
self.assertTrue(r.beginRender()) self.assertTrue(r.beginRender())