Skip to content

Commit c91fd5a

Browse files
committedJan 23, 2018
[reports] Tweak sub-section logic for multi-layer reports
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.
1 parent 8880861 commit c91fd5a

File tree

7 files changed

+315
-28
lines changed

7 files changed

+315
-28
lines changed
 

‎python/core/layout/qgsabstractreportsection.sip.in

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ class QgsReportSectionContext
3232

3333
QgsVectorLayer *currentLayer;
3434

35+
QVariantMap fieldFilters;
3536
};
3637

3738
class QgsAbstractReportSection : QgsAbstractLayoutIterator
@@ -122,16 +123,20 @@ Returns the associated project.
122123
Resets the section, ready for a new iteration.
123124
%End
124125

125-
virtual void prepareHeader();
126+
virtual bool prepareHeader();
126127
%Docstring
127-
Called just before rendering the section's header.
128+
Called just before rendering the section's header. Should return true if the header
129+
is to be included for this section, or false to skip the header for the current
130+
section.
128131

129132
.. seealso:: :py:func:`prepareFooter`
130133
%End
131134

132-
virtual void prepareFooter();
135+
virtual bool prepareFooter();
133136
%Docstring
134-
Called just before rendering the section's footer.
137+
Called just before rendering the section's footer. Should return true if the footer
138+
is to be included for this section, or false to skip the footerfor the current
139+
section.
135140

136141
.. seealso:: :py:func:`prepareHeader`
137142
%End

‎python/core/layout/qgsreportsectionfieldgroup.sip.in

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,9 @@ ascending, or false for descending sort.
134134

135135
virtual bool beginRender();
136136

137-
virtual void prepareHeader();
137+
virtual bool prepareHeader();
138+
139+
virtual bool prepareFooter();
138140

139141
virtual QgsLayout *nextBody( bool &ok );
140142

‎src/core/layout/qgsabstractreportsection.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,11 @@ bool QgsAbstractReportSection::next()
215215
// if we have a header, then the current section will be the header
216216
if ( mHeaderEnabled && mHeader )
217217
{
218-
prepareHeader();
219-
mCurrentLayout = mHeader.get();
220-
return true;
218+
if ( prepareHeader() )
219+
{
220+
mCurrentLayout = mHeader.get();
221+
return true;
222+
}
221223
}
222224

223225
// but if not, then the current section is a body
@@ -296,9 +298,11 @@ bool QgsAbstractReportSection::next()
296298
// if we have a footer, then the current section will be the footer
297299
if ( mFooterEnabled && mFooter )
298300
{
299-
prepareFooter();
300-
mCurrentLayout = mFooter.get();
301-
return true;
301+
if ( prepareFooter() )
302+
{
303+
mCurrentLayout = mFooter.get();
304+
return true;
305+
}
302306
}
303307

304308
// if not, then we're all done
@@ -338,6 +342,16 @@ void QgsAbstractReportSection::reset()
338342
}
339343
}
340344

345+
bool QgsAbstractReportSection::prepareHeader()
346+
{
347+
return true;
348+
}
349+
350+
bool QgsAbstractReportSection::prepareFooter()
351+
{
352+
return true;
353+
}
354+
341355
void QgsAbstractReportSection::setHeader( QgsLayout *header )
342356
{
343357
mHeader.reset( header );

‎src/core/layout/qgsabstractreportsection.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ class CORE_EXPORT QgsReportSectionContext
4444
//! Current coverage layer
4545
QgsVectorLayer *currentLayer = nullptr;
4646

47-
//! Current layer filters
48-
QMap< QgsVectorLayer *, QString > layerFilters SIP_SKIP;
47+
//! Current field filters
48+
QVariantMap fieldFilters;
4949
};
5050

5151
/**
@@ -135,16 +135,20 @@ class CORE_EXPORT QgsAbstractReportSection : public QgsAbstractLayoutIterator
135135
virtual void reset();
136136

137137
/**
138-
* Called just before rendering the section's header.
138+
* Called just before rendering the section's header. Should return true if the header
139+
* is to be included for this section, or false to skip the header for the current
140+
* section.
139141
* \see prepareFooter()
140142
*/
141-
virtual void prepareHeader() {}
143+
virtual bool prepareHeader();
142144

143145
/**
144-
* Called just before rendering the section's footer.
146+
* Called just before rendering the section's footer. Should return true if the footer
147+
* is to be included for this section, or false to skip the footerfor the current
148+
* section.
145149
* \see prepareHeader()
146150
*/
147-
virtual void prepareFooter() {}
151+
virtual bool prepareFooter();
148152

149153
/**
150154
* Returns the next body layout to export, or a nullptr if

‎src/core/layout/qgsreportsectionfieldgroup.cpp

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,10 @@ bool QgsReportSectionFieldGroup::beginRender()
7777
return QgsAbstractReportSection::beginRender();
7878
}
7979

80-
void QgsReportSectionFieldGroup::prepareHeader()
80+
bool QgsReportSectionFieldGroup::prepareHeader()
8181
{
8282
if ( !header() )
83-
return;
83+
return false;
8484

8585
if ( !mFeatures.isValid() )
8686
{
@@ -93,6 +93,13 @@ void QgsReportSectionFieldGroup::prepareHeader()
9393
header()->reportContext().blockSignals( false );
9494
header()->reportContext().setFeature( mHeaderFeature );
9595
mSkipNextRequest = true;
96+
mNoFeatures = !mHeaderFeature.isValid();
97+
return !mNoFeatures;
98+
}
99+
100+
bool QgsReportSectionFieldGroup::prepareFooter()
101+
{
102+
return !mNoFeatures;
96103
}
97104

98105
QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok )
@@ -153,6 +160,7 @@ void QgsReportSectionFieldGroup::reset()
153160
mHeaderFeature = QgsFeature();
154161
mLastFeature = QgsFeature();
155162
mFeatures = QgsFeatureIterator();
163+
mNoFeatures = false;
156164
}
157165

158166
void QgsReportSectionFieldGroup::setParentSection( QgsAbstractReportSection *parent )
@@ -227,9 +235,25 @@ void QgsReportSectionFieldGroup::setSortAscending( bool sortAscending )
227235
QgsFeatureRequest QgsReportSectionFieldGroup::buildFeatureRequest() const
228236
{
229237
QgsFeatureRequest request;
230-
QString filter = context().layerFilters.value( mCoverageLayer.get() );
231-
if ( !filter.isEmpty() )
232-
request.setFilterExpression( filter );
238+
QVariantMap filter = context().fieldFilters;
239+
240+
QStringList filterParts;
241+
for ( auto filterIt = filter.constBegin(); filterIt != filter.constEnd(); ++filterIt )
242+
{
243+
// use lookupField since we don't want case sensitivity
244+
int fieldIndex = mCoverageLayer->fields().lookupField( filterIt.key() );
245+
if ( fieldIndex >= 0 )
246+
{
247+
// layer has a matching field, so we need to filter by it
248+
filterParts << QgsExpression::createFieldEqualityExpression( mCoverageLayer->fields().at( fieldIndex ).name(), filterIt.value() );
249+
}
250+
}
251+
if ( !filterParts.empty() )
252+
{
253+
QString filterString = QStringLiteral( "(%1)" ).arg( filterParts.join( QStringLiteral( ") AND (" ) ) );
254+
request.setFilterExpression( filterString );
255+
}
256+
233257
request.addOrderBy( mField, mSortAscending );
234258
return request;
235259
}
@@ -261,10 +285,9 @@ void QgsReportSectionFieldGroup::updateChildContexts( const QgsFeature &feature
261285
if ( mCoverageLayer )
262286
c.currentLayer = mCoverageLayer.get();
263287

264-
QString currentFilter = c.layerFilters.value( mCoverageLayer.get() );
265-
QString thisFilter = QgsExpression::createFieldEqualityExpression( mField, feature.attribute( mFieldIndex ) );
266-
QString newFilter = currentFilter.isEmpty() ? thisFilter : QStringLiteral( "(%1) AND (%2)" ).arg( currentFilter, thisFilter );
267-
c.layerFilters[ mCoverageLayer.get() ] = newFilter;
288+
QVariantMap currentFilter = c.fieldFilters;
289+
currentFilter.insert( mField, feature.attribute( mFieldIndex ) );
290+
c.fieldFilters = currentFilter;
268291

269292
const QList< QgsAbstractReportSection * > sections = childSections();
270293
for ( QgsAbstractReportSection *section : qgis::as_const( sections ) )

‎src/core/layout/qgsreportsectionfieldgroup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection
122122

123123
QgsReportSectionFieldGroup *clone() const override SIP_FACTORY;
124124
bool beginRender() override;
125-
void prepareHeader() override;
126-
//void prepareFooter() override;
125+
bool prepareHeader() override;
126+
bool prepareFooter() override;
127127
QgsLayout *nextBody( bool &ok ) override;
128128
void reset() override;
129129
void setParentSection( QgsAbstractReportSection *parentSection ) override;
@@ -142,6 +142,7 @@ class CORE_EXPORT QgsReportSectionFieldGroup : public QgsAbstractReportSection
142142
int mFieldIndex = -1;
143143
QgsFeatureIterator mFeatures;
144144
bool mSkipNextRequest = false;
145+
bool mNoFeatures = false;
145146
QgsFeature mHeaderFeature;
146147
QgsFeature mLastFeature;
147148
QSet< QVariant > mEncounteredValues;

0 commit comments

Comments
 (0)
Please sign in to comment.