Skip to content
Permalink
Browse files

Fix missing feature contexts for report section header/footers

and expand unit tests
  • Loading branch information
nyalldawson committed Jan 2, 2018
1 parent 4e45639 commit 5d64f3cd2265889b3278905da4bb4556fea6337c
@@ -28,6 +28,16 @@ exposed to the Python bindings for unit testing purposes only.
%End
public:

QgsFeature feature;
%Docstring
Current feature
%End

QgsVectorLayer *currentLayer;
%Docstring
Current coverage layer
%End

};

class QgsAbstractReportSection : QgsAbstractLayoutIterator
@@ -111,6 +121,20 @@ Returns the associated project.
virtual void reset();
%Docstring
Resets the section, ready for a new iteration.
%End

virtual void prepareHeader();
%Docstring
Called just before rendering the section's header.

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

virtual void prepareFooter();
%Docstring
Called just before rendering the section's footer.

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

virtual QgsLayout *nextBody( bool &ok /Out/ );
@@ -101,6 +101,8 @@ ascending, or false for descending sort.

virtual bool beginRender();

virtual void prepareHeader();

virtual QgsLayout *nextBody( bool &ok );

virtual void reset();
@@ -52,7 +52,23 @@ QgsProject *QgsAbstractReportSection::project()

void QgsAbstractReportSection::setContext( const QgsReportSectionContext &context )
{
auto setReportContext = [&context]( QgsLayout * layout )
{
if ( context.currentLayer )
{
layout->reportContext().blockSignals( true );
layout->reportContext().setLayer( context.currentLayer );
layout->reportContext().blockSignals( false );
}
layout->reportContext().setFeature( context.feature );
};

mContext = context;
if ( mHeader )
setReportContext( mHeader.get() );
if ( mFooter )
setReportContext( mFooter.get() );

for ( QgsAbstractReportSection *section : qgis::as_const( mChildren ) )
{
section->setContext( mContext );
@@ -191,6 +207,7 @@ bool QgsAbstractReportSection::next()
// if we have a header, then the current section will be the header
if ( mHeaderEnabled && mHeader )
{
prepareHeader();
mCurrentLayout = mHeader.get();
return true;
}
@@ -271,6 +288,7 @@ bool QgsAbstractReportSection::next()
// if we have a footer, then the current section will be the footer
if ( mFooterEnabled && mFooter )
{
prepareFooter();
mCurrentLayout = mFooter.get();
return true;
}
@@ -38,6 +38,12 @@ class CORE_EXPORT QgsReportSectionContext
{
public:

//! Current feature
QgsFeature feature;

//! Current coverage layer
QgsVectorLayer *currentLayer = nullptr;

//! Current layer filters
QMap< QgsVectorLayer *, QString > layerFilters SIP_SKIP;
};
@@ -123,6 +129,18 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
*/
virtual void reset();

/**
* Called just before rendering the section's header.
* \see prepareFooter()
*/
virtual void prepareHeader() {}

/**
* Called just before rendering the section's footer.
* \see prepareHeader()
*/
virtual void prepareFooter() {}

/**
* Returns the next body layout to export, or a nullptr if
* no body layout is required this iteration.
@@ -68,22 +68,60 @@ bool QgsReportSectionFieldGroup::beginRender()
return QgsAbstractReportSection::beginRender();
}

void QgsReportSectionFieldGroup::prepareHeader()
{
if ( !header() )
return;

if ( !mFeatures.isValid() )
{
mFeatures = mCoverageLayer->getFeatures( buildFeatureRequest() );
}

mHeaderFeature = getNextFeature();
header()->reportContext().blockSignals( true );
header()->reportContext().setLayer( mCoverageLayer.get() );
header()->reportContext().blockSignals( false );
header()->reportContext().setFeature( mHeaderFeature );
mSkipNextRequest = true;
}

QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok )
{
if ( !mFeatures.isValid() )
{
mFeatures = mCoverageLayer->getFeatures( buildFeatureRequest() );
}

QgsFeature f = getNextFeature();
QgsFeature f;
if ( !mSkipNextRequest )
{
f = getNextFeature();
}
else
{
f = mHeaderFeature;
mSkipNextRequest = false;
}

if ( !f.isValid() )
{
// no features left for this iteration
mFeatures = QgsFeatureIterator();

if ( footer() )
{
footer()->reportContext().blockSignals( true );
footer()->reportContext().setLayer( mCoverageLayer.get() );
footer()->reportContext().blockSignals( false );
footer()->reportContext().setFeature( mLastFeature );
}
ok = false;
return nullptr;
}

mLastFeature = f;

updateChildContexts( f );

ok = true;
@@ -102,6 +140,10 @@ void QgsReportSectionFieldGroup::reset()
{
QgsAbstractReportSection::reset();
mEncounteredValues.clear();
mSkipNextRequest = false;
mHeaderFeature = QgsFeature();
mLastFeature = QgsFeature();
mFeatures = QgsFeatureIterator();
}

void QgsReportSectionFieldGroup::setParentSection( QgsAbstractReportSection *parent )
@@ -199,6 +241,10 @@ QgsFeature QgsReportSectionFieldGroup::getNextFeature()
void QgsReportSectionFieldGroup::updateChildContexts( const QgsFeature &feature )
{
QgsReportSectionContext c = context();
c.feature = feature;
if ( mCoverageLayer )
c.currentLayer = mCoverageLayer.get();

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 );
@@ -100,6 +100,8 @@ class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection

QgsReportSectionFieldGroup *clone() const override SIP_FACTORY;
bool beginRender() override;
void prepareHeader() override;
//void prepareFooter() override;
QgsLayout *nextBody( bool &ok ) override;
void reset() override;
void setParentSection( QgsAbstractReportSection *parentSection ) override;
@@ -116,6 +118,9 @@ class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection
bool mSortAscending = true;
int mFieldIndex = -1;
QgsFeatureIterator mFeatures;
bool mSkipNextRequest = false;
QgsFeature mHeaderFeature;
QgsFeature mLastFeature;
QSet< QVariant > mEncounteredValues;

std::unique_ptr< QgsLayout > mBody;

0 comments on commit 5d64f3c

Please sign in to comment.
You can’t perform that action at this time.