Skip to content

Commit

Permalink
Implement serialization of reports
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Jan 5, 2018
1 parent 6f2c63f commit 2654454
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 9 deletions.
47 changes: 46 additions & 1 deletion python/core/layout/qgsabstractreportsection.sip
Expand Up @@ -45,6 +45,14 @@ exposed to the Python bindings for unit testing purposes only.

%TypeHeaderCode
#include "qgsabstractreportsection.h"
%End
%ConvertToSubClassCode
if ( dynamic_cast< QgsReportSectionFieldGroup * >( sipCpp ) )
sipType = sipType_QgsReportSectionFieldGroup;
else if ( dynamic_cast< QgsReportSectionLayout * >( sipCpp ) )
sipType = sipType_QgsReportSectionLayout;
else
sipType = NULL;
%End
public:

Expand All @@ -58,6 +66,11 @@ Note that ownership is not transferred to ``parent``.



virtual QString type() const = 0;
%Docstring
Returns the section subclass type.
%End

virtual QgsAbstractReportSection *clone() const = 0 /Factory/;
%Docstring
Clones the report section. Ownership of the returned section is
Expand Down Expand Up @@ -272,6 +285,20 @@ Sets the current ``context`` for this section.
Returns the current context for this section.

.. seealso:: :py:func:`setContext()`
%End

bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Stores the section state in a DOM element.

.. seealso:: :py:func:`readXml()`
%End

bool readXml( const QDomElement &sectionElement, const QDomDocument &document, const QgsReadWriteContext &context );
%Docstring
Sets the item state from a DOM element.

.. seealso:: :py:func:`writeXml()`
%End

protected:
Expand All @@ -291,9 +318,27 @@ 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 );
virtual void setParentSection( QgsAbstractReportSection *parent );
%Docstring
Sets the ``parent`` report section.
%End

virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
%Docstring
Stores section state within an XML DOM element.

.. seealso:: :py:func:`writeXml()`

.. seealso:: :py:func:`readPropertiesFromElement()`
%End

virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
%Docstring
Sets section state from a DOM element.

.. seealso:: :py:func:`writePropertiesToElement()`

.. seealso:: :py:func:`readXml()`
%End

private:
Expand Down
1 change: 1 addition & 0 deletions python/core/layout/qgsreport.sip
Expand Up @@ -38,6 +38,7 @@ Constructor for QgsReport, associated with the specified
Note that ownership is not transferred to ``project``.
%End

virtual QString type() const;
virtual QgsProject *layoutProject() const;
virtual QgsReport *clone() const /Factory/;

Expand Down
11 changes: 11 additions & 0 deletions python/core/layout/qgsreportsectionfieldgroup.sip
Expand Up @@ -34,6 +34,8 @@ Constructor for QgsReportSectionFieldGroup, attached to the specified ``parent``
Note that ownership is not transferred to ``parent``.
%End

virtual QString type() const;

QgsLayout *body();
%Docstring
Returns the body layout for the section.
Expand Down Expand Up @@ -85,6 +87,15 @@ Sets the ``field`` associated with this section.

virtual void reset();

virtual void setParentSection( QgsAbstractReportSection *parent );


protected:

virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;

virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );


};

Expand Down
9 changes: 9 additions & 0 deletions python/core/layout/qgsreportsectionlayout.sip
Expand Up @@ -33,6 +33,8 @@ Constructor for QgsReportSectionLayout, attached to the specified ``parent`` sec
Note that ownership is not transferred to ``parent``.
%End

virtual QString type() const;

QgsLayout *body();
%Docstring
Returns the body layout for the section.
Expand All @@ -55,6 +57,13 @@ is transferred to the report section.
virtual QgsLayout *nextBody( bool &ok );


protected:

virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;

virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );


};


Expand Down
105 changes: 103 additions & 2 deletions src/core/layout/qgsabstractreportsection.cpp
Expand Up @@ -17,6 +17,8 @@
#include "qgsabstractreportsection.h"
#include "qgslayout.h"
#include "qgsreport.h"
#include "qgsreportsectionfieldgroup.h"
#include "qgsreportsectionlayout.h"

///@cond NOT_STABLE

Expand Down Expand Up @@ -54,6 +56,95 @@ void QgsAbstractReportSection::setContext( const QgsReportSectionContext &contex
}
}

bool QgsAbstractReportSection::writeXml( QDomElement &parentElement, QDomDocument &doc, const QgsReadWriteContext &context ) const
{
QDomElement element = doc.createElement( QStringLiteral( "Section" ) );
element.setAttribute( QStringLiteral( "type" ), type() );

element.setAttribute( QStringLiteral( "headerEnabled" ), mHeaderEnabled ? "1" : "0" );
if ( mHeader )
{
QDomElement headerElement = doc.createElement( QStringLiteral( "header" ) );
headerElement.appendChild( mHeader->writeXml( doc, context ) );
element.appendChild( headerElement );
}
element.setAttribute( QStringLiteral( "footerEnabled" ), mFooterEnabled ? "1" : "0" );
if ( mFooter )
{
QDomElement footerElement = doc.createElement( QStringLiteral( "footer" ) );
footerElement.appendChild( mFooter->writeXml( doc, context ) );
element.appendChild( footerElement );
}

for ( QgsAbstractReportSection *section : mChildren )
{
section->writeXml( element, doc, context );
}

writePropertiesToElement( element, doc, context );

parentElement.appendChild( element );
return true;
}

bool QgsAbstractReportSection::readXml( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context )
{
if ( element.nodeName() != QStringLiteral( "Section" ) )
{
return false;
}

mHeaderEnabled = element.attribute( QStringLiteral( "headerEnabled" ), "0" ).toInt();
mFooterEnabled = element.attribute( QStringLiteral( "footerEnabled" ), "0" ).toInt();
const QDomElement headerElement = element.firstChildElement( QStringLiteral( "header" ) );
if ( !headerElement.isNull() )
{
const QDomElement headerLayoutElem = headerElement.firstChild().toElement();
std::unique_ptr< QgsLayout > header = qgis::make_unique< QgsLayout >( project() );
header->readXml( headerLayoutElem, doc, context );
mHeader = std::move( header );
}
const QDomElement footerElement = element.firstChildElement( QStringLiteral( "footer" ) );
if ( !footerElement.isNull() )
{
const QDomElement footerLayoutElem = footerElement.firstChild().toElement();
std::unique_ptr< QgsLayout > footer = qgis::make_unique< QgsLayout >( project() );
footer->readXml( footerLayoutElem, doc, context );
mFooter = std::move( footer );
}

const QDomNodeList sectionItemList = element.childNodes();
for ( int i = 0; i < sectionItemList.size(); ++i )
{
const QDomElement currentSectionElem = sectionItemList.at( i ).toElement();
if ( currentSectionElem.nodeName() != QStringLiteral( "Section" ) )
continue;

const QString sectionType = currentSectionElem.attribute( QStringLiteral( "type" ) );

//TODO - eventually move this to a registry when there's enough subclasses to warrant it
std::unique_ptr< QgsAbstractReportSection > section;
if ( sectionType == QLatin1String( "SectionFieldGroup" ) )
{
section = qgis::make_unique< QgsReportSectionFieldGroup >();
}
else if ( sectionType == QLatin1String( "SectionLayout" ) )
{
section = qgis::make_unique< QgsReportSectionLayout >();
}

if ( section )
{
appendChild( section.get() );
section->readXml( currentSectionElem, doc, context );
( void )section.release(); //ownership was transferred already
}
}

bool result = readPropertiesFromElement( element, doc, context );
return result;
}

QString QgsAbstractReportSection::filePath( const QString &baseFilePath, const QString &extension )
{
QString base = QStringLiteral( "%1_%2" ).arg( baseFilePath ).arg( mSectionNumber, 4, 10, QChar( '0' ) );
Expand Down Expand Up @@ -235,13 +326,13 @@ QgsAbstractReportSection *QgsAbstractReportSection::childSection( int index )

void QgsAbstractReportSection::appendChild( QgsAbstractReportSection *section )
{
section->setParent( this );
section->setParentSection( this );
mChildren.append( section );
}

void QgsAbstractReportSection::insertChild( int index, QgsAbstractReportSection *section )
{
section->setParent( this );
section->setParentSection( this );
index = std::max( 0, index );
index = std::min( index, mChildren.count() );
mChildren.insert( index, section );
Expand Down Expand Up @@ -285,5 +376,15 @@ void QgsAbstractReportSection::copyCommonProperties( QgsAbstractReportSection *d
}
}

bool QgsAbstractReportSection::writePropertiesToElement( QDomElement &, QDomDocument &, const QgsReadWriteContext & ) const
{
return true;
}

bool QgsAbstractReportSection::readPropertiesFromElement( const QDomElement &, const QDomDocument &, const QgsReadWriteContext & )
{
return true;
}

///@endcond

44 changes: 43 additions & 1 deletion src/core/layout/qgsabstractreportsection.h
Expand Up @@ -53,6 +53,17 @@ class CORE_EXPORT QgsReportSectionContext
class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
{

#ifdef SIP_RUN
SIP_CONVERT_TO_SUBCLASS_CODE
if ( dynamic_cast< QgsReportSectionFieldGroup * >( sipCpp ) )
sipType = sipType_QgsReportSectionFieldGroup;
else if ( dynamic_cast< QgsReportSectionLayout * >( sipCpp ) )
sipType = sipType_QgsReportSectionLayout;
else
sipType = NULL;
SIP_END
#endif

public:

/**
Expand All @@ -69,6 +80,11 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
//! QgsAbstractReportSection cannot be copied
QgsAbstractReportSection &operator=( const QgsAbstractReportSection &other ) = delete;

/**
* Returns the section subclass type.
*/
virtual QString type() const = 0;

/**
* Clones the report section. Ownership of the returned section is
* transferred to the caller.
Expand Down Expand Up @@ -242,6 +258,18 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/
const QgsReportSectionContext &context() const { return mContext; }

/**
* Stores the section state in a DOM element.
* \see readXml()
*/
bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const;

/**
* Sets the item state from a DOM element.
* \see writeXml()
*/
bool readXml( const QDomElement &sectionElement, const QDomDocument &document, const QgsReadWriteContext &context );

protected:

//! Report sub-sections
Expand All @@ -263,7 +291,21 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
/**
* Sets the \a parent report section.
*/
void setParent( QgsAbstractReportSection *parent ) { mParent = parent; }
virtual void setParentSection( QgsAbstractReportSection *parent ) { mParent = parent; }

/**
* Stores section state within an XML DOM element.
* \see writeXml()
* \see readPropertiesFromElement()
*/
virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;

/**
* Sets section state from a DOM element.
* \see writePropertiesToElement()
* \see readXml()
*/
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );

private:

Expand Down
13 changes: 9 additions & 4 deletions src/core/layout/qgsreport.cpp
Expand Up @@ -40,15 +40,20 @@ void QgsReport::setName( const QString &name )
QDomElement QgsReport::writeLayoutXml( QDomDocument &document, const QgsReadWriteContext &context ) const
{
QDomElement element = document.createElement( QStringLiteral( "Report" ) );



writeXml( element, document, context );
element.setAttribute( QStringLiteral( "name" ), mName );
return element;
}

bool QgsReport::readLayoutXml( const QDomElement &layoutElement, const QDomDocument &document, const QgsReadWriteContext &context )
{

const QDomNodeList sectionList = layoutElement.elementsByTagName( QStringLiteral( "Section" ) );
if ( sectionList.count() > 0 )
{
readXml( sectionList.at( 0 ).toElement(), document, context );
}
setName( layoutElement.attribute( QStringLiteral( "name" ) ) );
return true;
}

///@endcond
Expand Down
1 change: 1 addition & 0 deletions src/core/layout/qgsreport.h
Expand Up @@ -52,6 +52,7 @@ class CORE_EXPORT QgsReport : public QObject, public QgsAbstractReportSection, p
*/
QgsReport( QgsProject *project );

QString type() const override { return QStringLiteral( "SectionReport" ); }
QgsProject *layoutProject() const override { return mProject; }
QgsReport *clone() const override SIP_FACTORY;
QString name() const override { return mName; }
Expand Down

0 comments on commit 2654454

Please sign in to comment.