Skip to content

Commit

Permalink
[reports] Tweak sub-section logic for multi-layer reports
Browse files Browse the repository at this point in the history
Instead of requiring a single layer for use with nested field group
sections, allow use of different layers. In this case the child
layers are filtered so that any fields with names matching their
parent groups are filtered to match the parent section's value.

Also only include headers and footers for child field group sections
if the child has matching features found.
  • Loading branch information
nyalldawson committed Jan 23, 2018
1 parent 8880861 commit c91fd5a
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 28 deletions.
13 changes: 9 additions & 4 deletions python/core/layout/qgsabstractreportsection.sip.in
Expand Up @@ -32,6 +32,7 @@ class QgsReportSectionContext

QgsVectorLayer *currentLayer;

QVariantMap fieldFilters;
};

class QgsAbstractReportSection : QgsAbstractLayoutIterator
Expand Down Expand Up @@ -122,16 +123,20 @@ Returns the associated project.
Resets the section, ready for a new iteration.
%End

virtual void prepareHeader();
virtual bool prepareHeader();
%Docstring
Called just before rendering the section's header.
Called just before rendering the section's header. Should return true if the header
is to be included for this section, or false to skip the header for the current
section.

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

virtual void prepareFooter();
virtual bool prepareFooter();
%Docstring
Called just before rendering the section's footer.
Called just before rendering the section's footer. Should return true if the footer
is to be included for this section, or false to skip the footerfor the current
section.

.. seealso:: :py:func:`prepareHeader`
%End
Expand Down
4 changes: 3 additions & 1 deletion python/core/layout/qgsreportsectionfieldgroup.sip.in
Expand Up @@ -134,7 +134,9 @@ ascending, or false for descending sort.

virtual bool beginRender();

virtual void prepareHeader();
virtual bool prepareHeader();

virtual bool prepareFooter();

virtual QgsLayout *nextBody( bool &ok );

Expand Down
26 changes: 20 additions & 6 deletions src/core/layout/qgsabstractreportsection.cpp
Expand Up @@ -215,9 +215,11 @@ 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;
if ( prepareHeader() )
{
mCurrentLayout = mHeader.get();
return true;
}
}

// but if not, then the current section is a body
Expand Down Expand Up @@ -296,9 +298,11 @@ 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;
if ( prepareFooter() )
{
mCurrentLayout = mFooter.get();
return true;
}
}

// if not, then we're all done
Expand Down Expand Up @@ -338,6 +342,16 @@ void QgsAbstractReportSection::reset()
}
}

bool QgsAbstractReportSection::prepareHeader()
{
return true;
}

bool QgsAbstractReportSection::prepareFooter()
{
return true;
}

void QgsAbstractReportSection::setHeader( QgsLayout *header )
{
mHeader.reset( header );
Expand Down
16 changes: 10 additions & 6 deletions src/core/layout/qgsabstractreportsection.h
Expand Up @@ -44,8 +44,8 @@ class CORE_EXPORT QgsReportSectionContext
//! Current coverage layer
QgsVectorLayer *currentLayer = nullptr;

//! Current layer filters
QMap< QgsVectorLayer *, QString > layerFilters SIP_SKIP;
//! Current field filters
QVariantMap fieldFilters;
};

/**
Expand Down Expand Up @@ -135,16 +135,20 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
virtual void reset();

/**
* Called just before rendering the section's header.
* Called just before rendering the section's header. Should return true if the header
* is to be included for this section, or false to skip the header for the current
* section.
* \see prepareFooter()
*/
virtual void prepareHeader() {}
virtual bool prepareHeader();

/**
* Called just before rendering the section's footer.
* Called just before rendering the section's footer. Should return true if the footer
* is to be included for this section, or false to skip the footerfor the current
* section.
* \see prepareHeader()
*/
virtual void prepareFooter() {}
virtual bool prepareFooter();

/**
* Returns the next body layout to export, or a nullptr if
Expand Down
41 changes: 32 additions & 9 deletions src/core/layout/qgsreportsectionfieldgroup.cpp
Expand Up @@ -77,10 +77,10 @@ bool QgsReportSectionFieldGroup::beginRender()
return QgsAbstractReportSection::beginRender();
}

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

if ( !mFeatures.isValid() )
{
Expand All @@ -93,6 +93,13 @@ void QgsReportSectionFieldGroup::prepareHeader()
header()->reportContext().blockSignals( false );
header()->reportContext().setFeature( mHeaderFeature );
mSkipNextRequest = true;
mNoFeatures = !mHeaderFeature.isValid();
return !mNoFeatures;
}

bool QgsReportSectionFieldGroup::prepareFooter()
{
return !mNoFeatures;
}

QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok )
Expand Down Expand Up @@ -153,6 +160,7 @@ void QgsReportSectionFieldGroup::reset()
mHeaderFeature = QgsFeature();
mLastFeature = QgsFeature();
mFeatures = QgsFeatureIterator();
mNoFeatures = false;
}

void QgsReportSectionFieldGroup::setParentSection( QgsAbstractReportSection *parent )
Expand Down Expand Up @@ -227,9 +235,25 @@ void QgsReportSectionFieldGroup::setSortAscending( bool sortAscending )
QgsFeatureRequest QgsReportSectionFieldGroup::buildFeatureRequest() const
{
QgsFeatureRequest request;
QString filter = context().layerFilters.value( mCoverageLayer.get() );
if ( !filter.isEmpty() )
request.setFilterExpression( filter );
QVariantMap filter = context().fieldFilters;

QStringList filterParts;
for ( auto filterIt = filter.constBegin(); filterIt != filter.constEnd(); ++filterIt )
{
// use lookupField since we don't want case sensitivity
int fieldIndex = mCoverageLayer->fields().lookupField( filterIt.key() );
if ( fieldIndex >= 0 )
{
// layer has a matching field, so we need to filter by it
filterParts << QgsExpression::createFieldEqualityExpression( mCoverageLayer->fields().at( fieldIndex ).name(), filterIt.value() );
}
}
if ( !filterParts.empty() )
{
QString filterString = QStringLiteral( "(%1)" ).arg( filterParts.join( QStringLiteral( ") AND (" ) ) );
request.setFilterExpression( filterString );
}

request.addOrderBy( mField, mSortAscending );
return request;
}
Expand Down Expand Up @@ -261,10 +285,9 @@ void QgsReportSectionFieldGroup::updateChildContexts( const QgsFeature &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 );
c.layerFilters[ mCoverageLayer.get() ] = newFilter;
QVariantMap currentFilter = c.fieldFilters;
currentFilter.insert( mField, feature.attribute( mFieldIndex ) );
c.fieldFilters = currentFilter;

const QList< QgsAbstractReportSection * > sections = childSections();
for ( QgsAbstractReportSection *section : qgis::as_const( sections ) )
Expand Down
5 changes: 3 additions & 2 deletions src/core/layout/qgsreportsectionfieldgroup.h
Expand Up @@ -122,8 +122,8 @@ class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection

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

0 comments on commit c91fd5a

Please sign in to comment.