Code shuffle and cleanup

This commit is contained in:
Nyall Dawson 2017-12-29 16:03:52 +10:00
parent 159986fdec
commit d8af098d83
14 changed files with 754 additions and 498 deletions

View File

@ -175,6 +175,9 @@
%Include layout/qgslayoutsnapper.sip
%Include layout/qgslayoutundocommand.sip
%Include layout/qgslayoututils.sip
%Include layout/qgsreport.sip
%Include layout/qgsreportsectionfieldgroup.sip
%Include layout/qgsreportsectionlayout.sip
%Include metadata/qgslayermetadata.sip
%Include metadata/qgslayermetadatavalidator.sip
%Include metadata/qgslayermetadataformatter.sip

View File

@ -10,8 +10,18 @@
class QgsReportContext
class QgsReportSectionContext
{
%Docstring
Current context for a report section.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsabstractreportsection.h"
@ -250,14 +260,14 @@ Removes the child section at the specified ``index``, deleting it.
.. seealso:: :py:func:`children()`
%End
void setContext( const QgsReportContext &context );
void setContext( const QgsReportSectionContext &context );
%Docstring
Sets the current ``context`` for this section.
.. seealso:: :py:func:`context()`
%End
const QgsReportContext &context() const;
const QgsReportSectionContext &context() const;
%Docstring
Returns the current context for this section.
@ -290,172 +300,6 @@ Sets the ``parent`` report section.
QgsAbstractReportSection( const QgsAbstractReportSection &other );
};
class QgsReportSectionLayout : QgsAbstractReportSection
{
%Docstring
A report section consisting of a single QgsLayout body.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsabstractreportsection.h"
%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.
.. seealso:: :py:func:`setBody()`
%End
void setBody( QgsLayout *body /Transfer/ );
%Docstring
Sets the ``body`` layout for the section. Ownership of ``body``
is transferred to the report section.
.. seealso:: :py:func:`body()`
%End
virtual QgsReportSectionLayout *clone() const /Factory/;
virtual bool beginRender();
virtual QgsLayout *nextBody( bool &ok );
};
class QgsReportSectionFieldGroup : QgsAbstractReportSection
{
%Docstring
A report section consisting of a features
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsabstractreportsection.h"
%End
public:
QgsReportSectionFieldGroup( QgsAbstractReportSection *parent = 0 );
%Docstring
Constructor for QgsReportSectionFieldGroup, 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.
.. seealso:: :py:func:`setBody()`
%End
void setBody( QgsLayout *body /Transfer/ );
%Docstring
Sets the ``body`` layout for the section. Ownership of ``body``
is transferred to the report section.
.. seealso:: :py:func:`body()`
%End
QgsVectorLayer *layer();
%Docstring
Returns the vector layer associated with this section.
.. seealso:: :py:func:`setLayer()`
%End
void setLayer( QgsVectorLayer *layer );
%Docstring
Sets the vector ``layer`` associated with this section.
.. seealso:: :py:func:`layer()`
%End
QString field() const;
%Docstring
Returns the field associated with this section.
.. seealso:: :py:func:`setField()`
%End
void setField( const QString &field );
%Docstring
Sets the ``field`` associated with this section.
.. seealso:: :py:func:`field()`
%End
virtual QgsReportSectionFieldGroup *clone() const /Factory/;
virtual bool beginRender();
virtual QgsLayout *nextBody( bool &ok );
virtual void reset();
};
class QgsReport : QgsAbstractReportSection
{
%Docstring
Represents a report for use with the QgsLayout engine.
Reports consist of multiple sections, represented by :py:class:`QgsAbstractReportSection`
subclasses.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsabstractreportsection.h"
%End
public:
QgsReport( QgsProject *project );
%Docstring
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/;
};
/************************************************************************
* This file has been generated automatically from *

View File

@ -0,0 +1,59 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreport.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsReport : QgsAbstractReportSection
{
%Docstring
Represents a report for use with the QgsLayout engine.
Reports consist of multiple sections, represented by QgsAbstractReportSection
subclasses.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsreport.h"
%End
public:
QgsReport( QgsProject *project );
%Docstring
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/;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreport.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,99 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreportsectionfieldgroup.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsReportSectionFieldGroup : QgsAbstractReportSection
{
%Docstring
A report section consisting of a features
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsreportsectionfieldgroup.h"
%End
public:
QgsReportSectionFieldGroup( QgsAbstractReportSection *parent = 0 );
%Docstring
Constructor for QgsReportSectionFieldGroup, 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.
.. seealso:: :py:func:`setBody()`
%End
void setBody( QgsLayout *body /Transfer/ );
%Docstring
Sets the ``body`` layout for the section. Ownership of ``body``
is transferred to the report section.
.. seealso:: :py:func:`body()`
%End
QgsVectorLayer *layer();
%Docstring
Returns the vector layer associated with this section.
.. seealso:: :py:func:`setLayer()`
%End
void setLayer( QgsVectorLayer *layer );
%Docstring
Sets the vector ``layer`` associated with this section.
.. seealso:: :py:func:`layer()`
%End
QString field() const;
%Docstring
Returns the field associated with this section.
.. seealso:: :py:func:`setField()`
%End
void setField( const QString &field );
%Docstring
Sets the ``field`` associated with this section.
.. seealso:: :py:func:`field()`
%End
virtual QgsReportSectionFieldGroup *clone() const /Factory/;
virtual bool beginRender();
virtual QgsLayout *nextBody( bool &ok );
virtual void reset();
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreportsectionfieldgroup.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,67 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreportsectionlayout.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsReportSectionLayout : QgsAbstractReportSection
{
%Docstring
A report section consisting of a single QgsLayout body.
.. warning::
This is not considered stable API, and may change in future QGIS releases. It is
exposed to the Python bindings for unit testing purposes only.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgsreportsectionlayout.h"
%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.
.. seealso:: :py:func:`setBody()`
%End
void setBody( QgsLayout *body /Transfer/ );
%Docstring
Sets the ``body`` layout for the section. Ownership of ``body``
is transferred to the report section.
.. seealso:: :py:func:`body()`
%End
virtual QgsReportSectionLayout *clone() const /Factory/;
virtual bool beginRender();
virtual QgsLayout *nextBody( bool &ok );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgsreportsectionlayout.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -415,6 +415,9 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutserializableobject.cpp
layout/qgslayoutsize.cpp
layout/qgsprintlayout.cpp
layout/qgsreport.cpp
layout/qgsreportsectionfieldgroup.cpp
layout/qgsreportsectionlayout.cpp
pal/costcalculator.cpp
pal/feature.cpp
@ -1045,6 +1048,9 @@ SET(QGIS_CORE_HDRS
layout/qgslayoutsnapper.h
layout/qgslayoutundocommand.h
layout/qgslayoututils.h
layout/qgsreport.h
layout/qgsreportsectionfieldgroup.h
layout/qgsreportsectionlayout.h
metadata/qgslayermetadata.h
metadata/qgslayermetadatavalidator.h

View File

@ -16,6 +16,7 @@
#include "qgsabstractreportsection.h"
#include "qgslayout.h"
#include "qgsreport.h"
///@cond NOT_STABLE
@ -44,7 +45,7 @@ QgsProject *QgsAbstractReportSection::project()
return nullptr;
}
void QgsAbstractReportSection::setContext( const QgsReportContext &context )
void QgsAbstractReportSection::setContext( const QgsReportSectionContext &context )
{
mContext = context;
for ( QgsAbstractReportSection *section : qgis::as_const( mChildren ) )
@ -274,173 +275,5 @@ void QgsAbstractReportSection::copyCommonProperties( QgsAbstractReportSection *d
}
}
// QgsReport
QgsReport::QgsReport( QgsProject *project )
: QgsAbstractReportSection( nullptr )
, mProject( project )
{}
QgsReport *QgsReport::clone() const
{
std::unique_ptr< QgsReport > copy = qgis::make_unique< QgsReport >( mProject );
copyCommonProperties( copy.get() );
return copy.release();
}
//
// QgsReportSectionLayout
//
QgsReportSectionLayout::QgsReportSectionLayout( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{}
QgsReportSectionLayout *QgsReportSectionLayout::clone() const
{
std::unique_ptr< QgsReportSectionLayout > copy = qgis::make_unique< QgsReportSectionLayout >( nullptr );
copyCommonProperties( copy.get() );
if ( mBody )
{
copy->mBody.reset( mBody->clone() );
}
else
copy->mBody.reset();
return copy.release();
}
bool QgsReportSectionLayout::beginRender()
{
mExportedBody = false;
return QgsAbstractReportSection::beginRender();
}
QgsLayout *QgsReportSectionLayout::nextBody( bool &ok )
{
if ( !mExportedBody && mBody )
{
mExportedBody = true;
ok = true;
return mBody.get();
}
else
{
ok = false;
return nullptr;
}
}
//
// QgsReportSectionFieldGroup
//
QgsReportSectionFieldGroup::QgsReportSectionFieldGroup( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{
}
QgsReportSectionFieldGroup *QgsReportSectionFieldGroup::clone() const
{
std::unique_ptr< QgsReportSectionFieldGroup > copy = qgis::make_unique< QgsReportSectionFieldGroup >( nullptr );
copyCommonProperties( copy.get() );
if ( mBody )
{
copy->mBody.reset( mBody->clone() );
}
else
copy->mBody.reset();
copy->setLayer( mCoverageLayer.get() );
copy->setField( mField );
return copy.release();
}
bool QgsReportSectionFieldGroup::beginRender()
{
if ( !mCoverageLayer.get() )
return false;
if ( !mField.isEmpty() )
{
mFieldIndex = mCoverageLayer->fields().lookupField( mField );
if ( mFieldIndex < 0 )
return false;
if ( mBody )
mBody->reportContext().setLayer( mCoverageLayer.get() );
mFeatures = QgsFeatureIterator();
}
return QgsAbstractReportSection::beginRender();
}
QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok )
{
if ( !mFeatures.isValid() )
{
QgsFeatureRequest request;
QString filter = context().layerFilters.value( mCoverageLayer.get() );
if ( !filter.isEmpty() )
request.setFilterExpression( filter );
request.addOrderBy( mField, true );
mFeatures = mCoverageLayer->getFeatures( request );
}
QgsFeature f;
QVariant currentValue;
bool first = true;
while ( first || ( !mBody && mEncounteredValues.contains( currentValue ) ) )
{
if ( !mFeatures.nextFeature( f ) )
{
// no features left for this iteration
mFeatures = QgsFeatureIterator();
ok = false;
return nullptr;
}
first = false;
currentValue = f.attribute( mFieldIndex );
}
mEncounteredValues.insert( currentValue );
QgsReportContext c = context();
QString currentFilter = c.layerFilters.value( mCoverageLayer.get() );
QString thisFilter = QgsExpression::createFieldEqualityExpression( mField, currentValue );
QString newFilter = currentFilter.isEmpty() ? thisFilter : QStringLiteral( "(%1) AND (%2)" ).arg( currentFilter, thisFilter );
c.layerFilters[ mCoverageLayer.get() ] = newFilter;
const QList< QgsAbstractReportSection * > sections = children();
for ( QgsAbstractReportSection *section : qgis::as_const( sections ) )
{
section->setContext( c );
}
ok = true;
if ( mBody )
{
mBody->reportContext().blockSignals( true );
mBody->reportContext().setLayer( mCoverageLayer.get() );
mBody->reportContext().blockSignals( false );
mBody->reportContext().setFeature( f );
}
return mBody.get();
}
void QgsReportSectionFieldGroup::reset()
{
QgsAbstractReportSection::reset();
mEncounteredValues.clear();
}
///@endcond

View File

@ -26,10 +26,19 @@
// This is not considered stable API - it is exposed to python bindings only for unit testing!
class CORE_EXPORT QgsReportContext
/**
* \ingroup core
* \class QgsReportSectionContext
* \brief Current context for a report section.
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsReportSectionContext
{
public:
//! Current layer filters
QMap< QgsVectorLayer *, QString > layerFilters SIP_SKIP;
};
@ -225,13 +234,13 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
* Sets the current \a context for this section.
* \see context()
*/
void setContext( const QgsReportContext &context );
void setContext( const QgsReportSectionContext &context );
/**
* Returns the current context for this section.
* \see setContext()
*/
const QgsReportContext &context() const { return mContext; }
const QgsReportSectionContext &context() const { return mContext; }
protected:
@ -272,169 +281,13 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
QList< QgsAbstractReportSection * > mChildren;
QgsReportContext mContext;
QgsReportSectionContext mContext;
#ifdef SIP_RUN
QgsAbstractReportSection( const QgsAbstractReportSection &other );
#endif
};
/**
* \ingroup core
* \class QgsReportSectionLayout
* \brief A report section consisting of a single QgsLayout body.
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
* \since QGIS 3.0
*/
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()
*/
QgsLayout *body() { return mBody.get(); }
/**
* Sets the \a body layout for the section. Ownership of \a body
* is transferred to the report section.
* \see body()
*/
void setBody( QgsLayout *body SIP_TRANSFER ) { mBody.reset( body ); }
QgsReportSectionLayout *clone() const override SIP_FACTORY;
bool beginRender() override;
QgsLayout *nextBody( bool &ok ) override;
private:
bool mExportedBody = false;
std::unique_ptr< QgsLayout > mBody;
};
/**
* \ingroup core
* \class QgsReportSectionFieldGroup
* \brief A report section consisting of a features
*
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection
{
public:
/**
* Constructor for QgsReportSectionFieldGroup, attached to the specified \a parent section.
* Note that ownership is not transferred to \a parent.
*/
QgsReportSectionFieldGroup( QgsAbstractReportSection *parent = nullptr );
/**
* Returns the body layout for the section.
* \see setBody()
*/
QgsLayout *body() { return mBody.get(); }
/**
* Sets the \a body layout for the section. Ownership of \a body
* is transferred to the report section.
* \see body()
*/
void setBody( QgsLayout *body SIP_TRANSFER ) { mBody.reset( body ); }
/**
* Returns the vector layer associated with this section.
* \see setLayer()
*/
QgsVectorLayer *layer() { return mCoverageLayer.get(); }
/**
* Sets the vector \a layer associated with this section.
* \see layer()
*/
void setLayer( QgsVectorLayer *layer ) { mCoverageLayer = layer; }
/**
* Returns the field associated with this section.
* \see setField()
*/
QString field() const { return mField; }
/**
* Sets the \a field associated with this section.
* \see field()
*/
void setField( const QString &field ) { mField = field; }
QgsReportSectionFieldGroup *clone() const override SIP_FACTORY;
bool beginRender() override;
QgsLayout *nextBody( bool &ok ) override;
void reset() override;
private:
QgsVectorLayerRef mCoverageLayer;
QString mField;
int mFieldIndex = -1;
QgsFeatureIterator mFeatures;
QSet< QVariant > mEncounteredValues;
std::unique_ptr< QgsLayout > mBody;
};
/**
* \ingroup core
* \class QgsReport
* \brief Represents a report for use with the QgsLayout engine.
*
* Reports consist of multiple sections, represented by QgsAbstractReportSection
* subclasses.
*
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsReport : public QgsAbstractReportSection
{
public:
/**
* 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;
};
///@endcond
#endif //QGSABSTRACTREPORTSECTION_H

View File

@ -0,0 +1,35 @@
/***************************************************************************
qgsreport.cpp
--------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsreport.h"
#include "qgslayout.h"
///@cond NOT_STABLE
QgsReport::QgsReport( QgsProject *project )
: QgsAbstractReportSection( nullptr )
, mProject( project )
{}
QgsReport *QgsReport::clone() const
{
std::unique_ptr< QgsReport > copy = qgis::make_unique< QgsReport >( mProject );
copyCommonProperties( copy.get() );
return copy.release();
}
///@endcond

View File

@ -0,0 +1,68 @@
/***************************************************************************
qgsreport.h
---------------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSREPORT_H
#define QGSREPORT_H
#include "qgis_core.h"
#include "qgsabstractreportsection.h"
///@cond NOT_STABLE
// This is not considered stable API - it is exposed to python bindings only for unit testing!
/**
* \ingroup core
* \class QgsReport
* \brief Represents a report for use with the QgsLayout engine.
*
* Reports consist of multiple sections, represented by QgsAbstractReportSection
* subclasses.
*
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsReport : public QgsAbstractReportSection
{
public:
/**
* 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;
};
///@endcond
#endif //QGSREPORT_H

View File

@ -0,0 +1,147 @@
/***************************************************************************
qgsreportsectionfieldgroup.cpp
--------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsreportsectionfieldgroup.h"
#include "qgslayout.h"
///@cond NOT_STABLE
QgsReportSectionFieldGroup::QgsReportSectionFieldGroup( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{
}
QgsReportSectionFieldGroup *QgsReportSectionFieldGroup::clone() const
{
std::unique_ptr< QgsReportSectionFieldGroup > copy = qgis::make_unique< QgsReportSectionFieldGroup >( nullptr );
copyCommonProperties( copy.get() );
if ( mBody )
{
copy->mBody.reset( mBody->clone() );
}
else
copy->mBody.reset();
copy->setLayer( mCoverageLayer.get() );
copy->setField( mField );
return copy.release();
}
bool QgsReportSectionFieldGroup::beginRender()
{
if ( !mCoverageLayer.get() )
return false;
if ( !mField.isEmpty() )
{
mFieldIndex = mCoverageLayer->fields().lookupField( mField );
if ( mFieldIndex < 0 )
return false;
if ( mBody )
mBody->reportContext().setLayer( mCoverageLayer.get() );
mFeatures = QgsFeatureIterator();
}
return QgsAbstractReportSection::beginRender();
}
QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok )
{
if ( !mFeatures.isValid() )
{
mFeatures = mCoverageLayer->getFeatures( buildFeatureRequest() );
}
QgsFeature f = getNextFeature();
if ( !f.isValid() )
{
// no features left for this iteration
mFeatures = QgsFeatureIterator();
ok = false;
return nullptr;
}
updateChildContexts( f );
ok = true;
if ( mBody )
{
mBody->reportContext().blockSignals( true );
mBody->reportContext().setLayer( mCoverageLayer.get() );
mBody->reportContext().blockSignals( false );
mBody->reportContext().setFeature( f );
}
return mBody.get();
}
void QgsReportSectionFieldGroup::reset()
{
QgsAbstractReportSection::reset();
mEncounteredValues.clear();
}
QgsFeatureRequest QgsReportSectionFieldGroup::buildFeatureRequest() const
{
QgsFeatureRequest request;
QString filter = context().layerFilters.value( mCoverageLayer.get() );
if ( !filter.isEmpty() )
request.setFilterExpression( filter );
request.addOrderBy( mField, true );
return request;
}
QgsFeature QgsReportSectionFieldGroup::getNextFeature()
{
QgsFeature f;
QVariant currentValue;
bool first = true;
while ( first || ( !mBody && mEncounteredValues.contains( currentValue ) ) )
{
if ( !mFeatures.nextFeature( f ) )
{
return QgsFeature();
}
first = false;
currentValue = f.attribute( mFieldIndex );
}
mEncounteredValues.insert( currentValue );
return f;
}
void QgsReportSectionFieldGroup::updateChildContexts( const QgsFeature &feature )
{
QgsReportSectionContext c = context();
QString currentFilter = c.layerFilters.value( mCoverageLayer.get() );
QString thisFilter = QgsExpression::createFieldEqualityExpression( mField, feature.attribute( mFieldIndex ) );
QString newFilter = currentFilter.isEmpty() ? thisFilter : QStringLiteral( "(%1) AND (%2)" ).arg( currentFilter, thisFilter );
c.layerFilters[ mCoverageLayer.get() ] = newFilter;
const QList< QgsAbstractReportSection * > sections = children();
for ( QgsAbstractReportSection *section : qgis::as_const( sections ) )
{
section->setContext( c );
}
}
///@endcond

View File

@ -0,0 +1,109 @@
/***************************************************************************
qgsreportsectionfieldgroup.h
---------------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSREPORTSECTIONFIELDGROUP_H
#define QGSREPORTSECTIONFIELDGROUP_H
#include "qgis_core.h"
#include "qgsabstractreportsection.h"
///@cond NOT_STABLE
// This is not considered stable API - it is exposed to python bindings only for unit testing!
/**
* \ingroup core
* \class QgsReportSectionFieldGroup
* \brief A report section consisting of a features
*
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
*
* \since QGIS 3.0
*/
class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection
{
public:
/**
* Constructor for QgsReportSectionFieldGroup, attached to the specified \a parent section.
* Note that ownership is not transferred to \a parent.
*/
QgsReportSectionFieldGroup( QgsAbstractReportSection *parent = nullptr );
/**
* Returns the body layout for the section.
* \see setBody()
*/
QgsLayout *body() { return mBody.get(); }
/**
* Sets the \a body layout for the section. Ownership of \a body
* is transferred to the report section.
* \see body()
*/
void setBody( QgsLayout *body SIP_TRANSFER ) { mBody.reset( body ); }
/**
* Returns the vector layer associated with this section.
* \see setLayer()
*/
QgsVectorLayer *layer() { return mCoverageLayer.get(); }
/**
* Sets the vector \a layer associated with this section.
* \see layer()
*/
void setLayer( QgsVectorLayer *layer ) { mCoverageLayer = layer; }
/**
* Returns the field associated with this section.
* \see setField()
*/
QString field() const { return mField; }
/**
* Sets the \a field associated with this section.
* \see field()
*/
void setField( const QString &field ) { mField = field; }
QgsReportSectionFieldGroup *clone() const override SIP_FACTORY;
bool beginRender() override;
QgsLayout *nextBody( bool &ok ) override;
void reset() override;
private:
QgsVectorLayerRef mCoverageLayer;
QString mField;
int mFieldIndex = -1;
QgsFeatureIterator mFeatures;
QSet< QVariant > mEncounteredValues;
std::unique_ptr< QgsLayout > mBody;
QgsFeatureRequest buildFeatureRequest() const;
QgsFeature getNextFeature();
void updateChildContexts( const QgsFeature &feature );
};
///@endcond
#endif //QGSREPORTSECTIONFIELDGROUP_H

View File

@ -0,0 +1,63 @@
/***************************************************************************
qgsreportsectionlayout.cpp
--------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsreportsectionlayout.h"
#include "qgslayout.h"
///@cond NOT_STABLE
QgsReportSectionLayout::QgsReportSectionLayout( QgsAbstractReportSection *parent )
: QgsAbstractReportSection( parent )
{}
QgsReportSectionLayout *QgsReportSectionLayout::clone() const
{
std::unique_ptr< QgsReportSectionLayout > copy = qgis::make_unique< QgsReportSectionLayout >( nullptr );
copyCommonProperties( copy.get() );
if ( mBody )
{
copy->mBody.reset( mBody->clone() );
}
else
copy->mBody.reset();
return copy.release();
}
bool QgsReportSectionLayout::beginRender()
{
mExportedBody = false;
return QgsAbstractReportSection::beginRender();
}
QgsLayout *QgsReportSectionLayout::nextBody( bool &ok )
{
if ( !mExportedBody && mBody )
{
mExportedBody = true;
ok = true;
return mBody.get();
}
else
{
ok = false;
return nullptr;
}
}
///@endcond

View File

@ -0,0 +1,70 @@
/***************************************************************************
qgsreportsectionlayout.h
---------------------------
begin : December 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSREPORTSECTIONLAYOUT_H
#define QGSREPORTSECTIONLAYOUT_H
#include "qgis_core.h"
#include "qgsabstractreportsection.h"
///@cond NOT_STABLE
// This is not considered stable API - it is exposed to python bindings only for unit testing!
/**
* \ingroup core
* \class QgsReportSectionLayout
* \brief A report section consisting of a single QgsLayout body.
* \warning This is not considered stable API, and may change in future QGIS releases. It is
* exposed to the Python bindings for unit testing purposes only.
* \since QGIS 3.0
*/
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()
*/
QgsLayout *body() { return mBody.get(); }
/**
* Sets the \a body layout for the section. Ownership of \a body
* is transferred to the report section.
* \see body()
*/
void setBody( QgsLayout *body SIP_TRANSFER ) { mBody.reset( body ); }
QgsReportSectionLayout *clone() const override SIP_FACTORY;
bool beginRender() override;
QgsLayout *nextBody( bool &ok ) override;
private:
bool mExportedBody = false;
std::unique_ptr< QgsLayout > mBody;
};
///@endcond
#endif //QGSREPORTSECTIONLAYOUT_H