Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsreportsectionfieldgroup.cpp 3 : : -------------------- 4 : : begin : December 2017 5 : : copyright : (C) 2017 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : /*************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #include "qgsreportsectionfieldgroup.h" 18 : : #include "qgslayout.h" 19 : : 20 : : ///@cond NOT_STABLE 21 : : 22 : 0 : QgsReportSectionFieldGroup::QgsReportSectionFieldGroup( QgsAbstractReportSection *parent ) 23 : 0 : : QgsAbstractReportSection( parent ) 24 : 0 : { 25 : : 26 : 0 : } 27 : : 28 : 0 : QString QgsReportSectionFieldGroup::description() const 29 : : { 30 : 0 : if ( mCoverageLayer.get() ) 31 : 0 : return QObject::tr( "Group: %1 - %2" ).arg( mCoverageLayer->name(), mField ); 32 : : else 33 : 0 : return QObject::tr( "Group" ); 34 : 0 : } 35 : : 36 : 0 : QIcon QgsReportSectionFieldGroup::icon() const 37 : : { 38 : 0 : return QgsApplication::getThemeIcon( QStringLiteral( "/mIconFieldText.svg" ) ); 39 : 0 : } 40 : : 41 : 0 : QgsReportSectionFieldGroup *QgsReportSectionFieldGroup::clone() const 42 : : { 43 : 0 : std::unique_ptr< QgsReportSectionFieldGroup > copy = std::make_unique< QgsReportSectionFieldGroup >( nullptr ); 44 : 0 : copyCommonProperties( copy.get() ); 45 : : 46 : 0 : if ( mBody ) 47 : : { 48 : 0 : copy->mBody.reset( mBody->clone() ); 49 : 0 : } 50 : : else 51 : 0 : copy->mBody.reset(); 52 : : 53 : 0 : copy->setLayer( mCoverageLayer.get() ); 54 : 0 : copy->setField( mField ); 55 : 0 : copy->setSortAscending( mSortAscending ); 56 : 0 : copy->setBodyEnabled( mBodyEnabled ); 57 : : 58 : 0 : return copy.release(); 59 : 0 : } 60 : : 61 : 0 : bool QgsReportSectionFieldGroup::beginRender() 62 : : { 63 : 0 : if ( !mCoverageLayer.get() ) 64 : 0 : return false; 65 : : 66 : 0 : if ( !mField.isEmpty() ) 67 : : { 68 : 0 : mFieldIndex = mCoverageLayer->fields().lookupField( mField ); 69 : 0 : if ( mFieldIndex < 0 ) 70 : 0 : return false; 71 : : 72 : 0 : if ( mBody ) 73 : 0 : mBody->reportContext().setLayer( mCoverageLayer.get() ); 74 : : 75 : 0 : mFeatures = QgsFeatureIterator(); 76 : 0 : } 77 : 0 : return QgsAbstractReportSection::beginRender(); 78 : 0 : } 79 : : 80 : 0 : bool QgsReportSectionFieldGroup::prepareHeader() 81 : : { 82 : 0 : if ( !header() ) 83 : 0 : return false; 84 : : 85 : 0 : if ( !mFeatures.isValid() ) 86 : : { 87 : 0 : mFeatures = mCoverageLayer->getFeatures( buildFeatureRequest() ); 88 : 0 : } 89 : : 90 : 0 : mHeaderFeature = getNextFeature(); 91 : 0 : header()->reportContext().blockSignals( true ); 92 : 0 : header()->reportContext().setLayer( mCoverageLayer.get() ); 93 : 0 : header()->reportContext().blockSignals( false ); 94 : 0 : header()->reportContext().setFeature( mHeaderFeature ); 95 : 0 : mSkipNextRequest = true; 96 : 0 : mNoFeatures = !mHeaderFeature.isValid(); 97 : 0 : return mHeaderVisibility == AlwaysInclude || !mNoFeatures; 98 : 0 : } 99 : : 100 : 0 : bool QgsReportSectionFieldGroup::prepareFooter() 101 : : { 102 : 0 : return mFooterVisibility == AlwaysInclude || !mNoFeatures; 103 : : } 104 : : 105 : 0 : QgsLayout *QgsReportSectionFieldGroup::nextBody( bool &ok ) 106 : : { 107 : 0 : if ( !mFeatures.isValid() ) 108 : : { 109 : 0 : mFeatures = mCoverageLayer->getFeatures( buildFeatureRequest() ); 110 : 0 : } 111 : : 112 : 0 : QgsFeature f; 113 : 0 : if ( !mSkipNextRequest ) 114 : : { 115 : 0 : f = getNextFeature(); 116 : 0 : } 117 : : else 118 : : { 119 : 0 : f = mHeaderFeature; 120 : 0 : mSkipNextRequest = false; 121 : : } 122 : : 123 : 0 : if ( !f.isValid() ) 124 : : { 125 : : // no features left for this iteration 126 : 0 : mFeatures = QgsFeatureIterator(); 127 : : 128 : 0 : if ( auto *lFooter = footer() ) 129 : : { 130 : 0 : lFooter->reportContext().blockSignals( true ); 131 : 0 : lFooter->reportContext().setLayer( mCoverageLayer.get() ); 132 : 0 : lFooter->reportContext().blockSignals( false ); 133 : 0 : lFooter->reportContext().setFeature( mLastFeature ); 134 : 0 : } 135 : 0 : ok = false; 136 : 0 : return nullptr; 137 : : } 138 : : 139 : 0 : mLastFeature = f; 140 : : 141 : 0 : updateChildContexts( f ); 142 : : 143 : 0 : ok = true; 144 : 0 : if ( mBody && mBodyEnabled ) 145 : : { 146 : 0 : mBody->reportContext().blockSignals( true ); 147 : 0 : mBody->reportContext().setLayer( mCoverageLayer.get() ); 148 : 0 : mBody->reportContext().blockSignals( false ); 149 : 0 : mBody->reportContext().setFeature( f ); 150 : 0 : } 151 : : 152 : 0 : return mBodyEnabled ? mBody.get() : nullptr; 153 : 0 : } 154 : : 155 : 0 : void QgsReportSectionFieldGroup::reset() 156 : : { 157 : 0 : QgsAbstractReportSection::reset(); 158 : 0 : mEncounteredValues.clear(); 159 : 0 : mSkipNextRequest = false; 160 : 0 : mHeaderFeature = QgsFeature(); 161 : 0 : mLastFeature = QgsFeature(); 162 : 0 : mFeatures = QgsFeatureIterator(); 163 : 0 : mNoFeatures = false; 164 : 0 : } 165 : : 166 : 0 : void QgsReportSectionFieldGroup::setParentSection( QgsAbstractReportSection *parent ) 167 : : { 168 : 0 : QgsAbstractReportSection::setParentSection( parent ); 169 : 0 : if ( !mCoverageLayer ) 170 : 0 : mCoverageLayer.resolveWeakly( project() ); 171 : 0 : } 172 : : 173 : 0 : void QgsReportSectionFieldGroup::reloadSettings() 174 : : { 175 : 0 : QgsAbstractReportSection::reloadSettings(); 176 : 0 : if ( mBody ) 177 : 0 : mBody->reloadSettings(); 178 : 0 : } 179 : 0 : 180 : 0 : bool QgsReportSectionFieldGroup::writePropertiesToElement( QDomElement &element, QDomDocument &doc, const QgsReadWriteContext &context ) const 181 : 0 : { 182 : 0 : element.setAttribute( QStringLiteral( "headerVisibility" ), static_cast< int >( mHeaderVisibility ) ); 183 : 0 : element.setAttribute( QStringLiteral( "footerVisibility" ), static_cast< int >( mFooterVisibility ) ); 184 : 0 : element.setAttribute( QStringLiteral( "field" ), mField ); 185 : 0 : element.setAttribute( QStringLiteral( "ascending" ), mSortAscending ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); 186 : 0 : element.setAttribute( QStringLiteral( "bodyEnabled" ), mBodyEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); 187 : 0 : if ( mCoverageLayer ) 188 : : { 189 : 0 : element.setAttribute( QStringLiteral( "coverageLayer" ), mCoverageLayer.layerId ); 190 : 0 : element.setAttribute( QStringLiteral( "coverageLayerName" ), mCoverageLayer.name ); 191 : 0 : element.setAttribute( QStringLiteral( "coverageLayerSource" ), mCoverageLayer.source ); 192 : 0 : element.setAttribute( QStringLiteral( "coverageLayerProvider" ), mCoverageLayer.provider ); 193 : 0 : } 194 : : 195 : 0 : if ( mBody ) 196 : : { 197 : 0 : QDomElement bodyElement = doc.createElement( QStringLiteral( "body" ) ); 198 : 0 : bodyElement.appendChild( mBody->writeXml( doc, context ) ); 199 : 0 : element.appendChild( bodyElement ); 200 : 0 : } 201 : 0 : return true; 202 : 0 : } 203 : : 204 : 0 : bool QgsReportSectionFieldGroup::readPropertiesFromElement( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context ) 205 : : { 206 : 0 : mHeaderVisibility = static_cast< SectionVisibility >( element.attribute( QStringLiteral( "headerVisibility" ) ).toInt() ); 207 : 0 : mFooterVisibility = static_cast< SectionVisibility >( element.attribute( QStringLiteral( "footerVisibility" ) ).toInt() ); 208 : 0 : mField = element.attribute( QStringLiteral( "field" ) ); 209 : 0 : mSortAscending = element.attribute( QStringLiteral( "ascending" ) ).toInt(); 210 : 0 : mBodyEnabled = element.attribute( QStringLiteral( "bodyEnabled" ) ).toInt(); 211 : 0 : QString layerId = element.attribute( QStringLiteral( "coverageLayer" ) ); 212 : 0 : QString layerName = element.attribute( QStringLiteral( "coverageLayerName" ) ); 213 : 0 : QString layerSource = element.attribute( QStringLiteral( "coverageLayerSource" ) ); 214 : 0 : QString layerProvider = element.attribute( QStringLiteral( "coverageLayerProvider" ) ); 215 : 0 : mCoverageLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider ); 216 : 0 : mCoverageLayer.resolveWeakly( project() ); 217 : : 218 : 0 : const QDomElement bodyElement = element.firstChildElement( QStringLiteral( "body" ) ); 219 : 0 : if ( !bodyElement.isNull() ) 220 : : { 221 : 0 : const QDomElement bodyLayoutElem = bodyElement.firstChild().toElement(); 222 : 0 : std::unique_ptr< QgsLayout > body = std::make_unique< QgsLayout >( project() ); 223 : 0 : body->readXml( bodyLayoutElem, doc, context ); 224 : 0 : mBody = std::move( body ); 225 : 0 : } 226 : : return true; 227 : 0 : } 228 : : 229 : 0 : bool QgsReportSectionFieldGroup::sortAscending() const 230 : : { 231 : 0 : return mSortAscending; 232 : : } 233 : : 234 : 0 : void QgsReportSectionFieldGroup::setSortAscending( bool sortAscending ) 235 : : { 236 : 0 : mSortAscending = sortAscending; 237 : 0 : } 238 : : 239 : 0 : QgsFeatureRequest QgsReportSectionFieldGroup::buildFeatureRequest() const 240 : : { 241 : 0 : QgsFeatureRequest request; 242 : 0 : QVariantMap filter = context().fieldFilters; 243 : : 244 : 0 : QStringList filterParts; 245 : 0 : for ( auto filterIt = filter.constBegin(); filterIt != filter.constEnd(); ++filterIt ) 246 : : { 247 : : // use lookupField since we don't want case sensitivity 248 : 0 : int fieldIndex = mCoverageLayer->fields().lookupField( filterIt.key() ); 249 : 0 : if ( fieldIndex >= 0 ) 250 : : { 251 : : // layer has a matching field, so we need to filter by it 252 : 0 : filterParts << QgsExpression::createFieldEqualityExpression( mCoverageLayer->fields().at( fieldIndex ).name(), filterIt.value() ); 253 : 0 : } 254 : 0 : } 255 : 0 : if ( !filterParts.empty() ) 256 : : { 257 : 0 : QString filterString = QStringLiteral( "(%1)" ).arg( filterParts.join( QLatin1String( ") AND (" ) ) ); 258 : 0 : request.setFilterExpression( filterString ); 259 : 0 : } 260 : : 261 : 0 : request.addOrderBy( mField, mSortAscending ); 262 : 0 : return request; 263 : 0 : } 264 : : 265 : 0 : QgsFeature QgsReportSectionFieldGroup::getNextFeature() 266 : : { 267 : 0 : QgsFeature f; 268 : 0 : QVariant currentValue; 269 : 0 : bool first = true; 270 : 0 : while ( first || ( ( !mBody || !mBodyEnabled ) && mEncounteredValues.contains( currentValue ) ) ) 271 : : { 272 : 0 : if ( !mFeatures.nextFeature( f ) ) 273 : : { 274 : 0 : return QgsFeature(); 275 : : } 276 : : 277 : 0 : first = false; 278 : 0 : currentValue = f.attribute( mFieldIndex ); 279 : : } 280 : : 281 : 0 : mEncounteredValues.insert( currentValue ); 282 : 0 : return f; 283 : 0 : } 284 : : 285 : 0 : void QgsReportSectionFieldGroup::updateChildContexts( const QgsFeature &feature ) 286 : : { 287 : 0 : QgsReportSectionContext c = context(); 288 : 0 : c.feature = feature; 289 : 0 : if ( mCoverageLayer ) 290 : 0 : c.currentLayer = mCoverageLayer.get(); 291 : : 292 : 0 : QVariantMap currentFilter = c.fieldFilters; 293 : 0 : currentFilter.insert( mField, feature.attribute( mFieldIndex ) ); 294 : 0 : c.fieldFilters = currentFilter; 295 : : 296 : 0 : const QList< QgsAbstractReportSection * > sections = childSections(); 297 : 0 : for ( QgsAbstractReportSection *section : std::as_const( sections ) ) 298 : : { 299 : 0 : section->setContext( c ); 300 : : } 301 : 0 : } 302 : : 303 : : ///@endcond 304 : :