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

View File

@ -17,11 +17,31 @@
#include "qgsabstractreportsection.h"
#include "qgslayout.h"
QgsAbstractReportSection::QgsAbstractReportSection( QgsAbstractReportSection *parent )
: mParent( parent )
{}
QgsAbstractReportSection::~QgsAbstractReportSection()
{
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 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 )
{
section->setParent( this );
mChildren.append( section );
}
void QgsAbstractReportSection::insertChild( int index, QgsAbstractReportSection *section )
{
section->setParent( this );
index = std::max( 0, index );
index = std::min( index, mChildren.count() );
mChildren.insert( index, section );
@ -202,16 +224,21 @@ void QgsAbstractReportSection::copyCommonProperties( QgsAbstractReportSection *d
for ( QgsAbstractReportSection *child : qgis::as_const( mChildren ) )
{
destination->mChildren.append( child->clone() );
destination->appendChild( child->clone() );
}
}
// QgsReport
QgsReport::QgsReport( QgsProject *project )
: QgsAbstractReportSection( nullptr )
, mProject( project )
{}
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() );
return copy.release();
}
@ -220,13 +247,19 @@ QgsReport *QgsReport::clone() const
// QgsReportSectionLayout
//
QgsReportSectionLayout::QgsReportSectionLayout( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{}
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() );
if ( mBody )
{
copy->mBody.reset( mBody->clone() );
}
else
copy->mBody.reset();

View File

@ -31,8 +31,11 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
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;
@ -51,6 +54,16 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/
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?
int count() override { return -1; }
@ -208,8 +221,15 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/
void copyCommonProperties( QgsAbstractReportSection *destination ) const;
/**
* Sets the \a parent report section.
*/
void setParent( QgsAbstractReportSection *parent ) { mParent = parent; }
private:
QgsAbstractReportSection *mParent = nullptr;
int mSectionNumber = 0;
SubSection mNextSection = Header;
int mNextChild = 0;
@ -237,6 +257,12 @@ class CORE_EXPORT QgsReportSectionLayout : public QgsAbstractReportSection
{
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.
* \see setBody()
@ -277,11 +303,25 @@ class CORE_EXPORT QgsReport : public QgsAbstractReportSection
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;
private:
QgsProject *mProject = nullptr;
};
#endif //QGSABSTRACTREPORTSECTION_H

View File

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

View File

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