int QgsAtlasComposition::updateFeatures() { //needs to be called when layer, filter, sort changes if ( !mCoverageLayer ) { return 0; } updateFilenameExpression(); // select all features with all attributes QgsFeatureIterator fit = mCoverageLayer->getFeatures(); std::auto_ptr<QgsExpression> filterExpression; if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) { filterExpression = std::auto_ptr<QgsExpression>( new QgsExpression( mFeatureFilter ) ); if ( filterExpression->hasParserError() ) { throw std::runtime_error( tr( "Feature filter parser error: %1" ).arg( filterExpression->parserErrorString() ).toLocal8Bit().data() ); } } // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process // We thus store the feature ids for future extraction QgsFeature feat; mFeatureIds.clear(); mFeatureKeys.clear(); while ( fit.nextFeature( feat ) ) { if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) { QVariant result = filterExpression->evaluate( &feat, mCoverageLayer->pendingFields() ); if ( filterExpression->hasEvalError() ) { throw std::runtime_error( tr( "Feature filter eval error: %1" ).arg( filterExpression->evalErrorString() ).toLocal8Bit().data() ); } // skip this feature if the filter evaluation if false if ( !result.toBool() ) { continue; } } mFeatureIds.push_back( feat.id() ); if ( mSortFeatures ) { mFeatureKeys.insert( feat.id(), feat.attributes()[ mSortKeyAttributeIdx ] ); } } // sort features, if asked for if ( mSortFeatures ) { FieldSorter sorter( mFeatureKeys, mSortAscending ); qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); } QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )mFeatureIds.size() ) ); //jump to first feature if currently using an atlas preview //need to do this in case filtering/layer change has altered matching features if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas ) { firstFeature(); } return mFeatureIds.size(); }
int QgsAtlasComposition::updateFeatures() { //needs to be called when layer, filter, sort changes if ( !mCoverageLayer ) { return 0; } QgsExpressionContext expressionContext = createExpressionContext(); updateFilenameExpression(); // select all features with all attributes QgsFeatureRequest req; QScopedPointer<QgsExpression> filterExpression; if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) { filterExpression.reset( new QgsExpression( mFeatureFilter ) ); if ( filterExpression->hasParserError() ) { mFilterParserError = filterExpression->parserErrorString(); return 0; } //filter good to go req.setFilterExpression( mFeatureFilter ); } mFilterParserError = QString(); QgsFeatureIterator fit = mCoverageLayer->getFeatures( req ); QScopedPointer<QgsExpression> nameExpression; if ( !mPageNameExpression.isEmpty() ) { nameExpression.reset( new QgsExpression( mPageNameExpression ) ); if ( nameExpression->hasParserError() ) { nameExpression.reset( nullptr ); } else { nameExpression->prepare( &expressionContext ); } } // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process // We thus store the feature ids for future extraction QgsFeature feat; mFeatureIds.clear(); mFeatureKeys.clear(); int sortIdx = mCoverageLayer->fields().lookupField( mSortKeyAttributeName ); while ( fit.nextFeature( feat ) ) { expressionContext.setFeature( feat ); QString pageName; if ( !nameExpression.isNull() ) { QVariant result = nameExpression->evaluate( &expressionContext ); if ( nameExpression->hasEvalError() ) { QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Composer" ) ); } pageName = result.toString(); } mFeatureIds.push_back( qMakePair( feat.id(), pageName ) ); if ( mSortFeatures && sortIdx != -1 ) { mFeatureKeys.insert( feat.id(), feat.attributes().at( sortIdx ) ); } } // sort features, if asked for if ( !mFeatureKeys.isEmpty() ) { FieldSorter sorter( mFeatureKeys, mSortAscending ); qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); } emit numberFeaturesChanged( mFeatureIds.size() ); //jump to first feature if currently using an atlas preview //need to do this in case filtering/layer change has altered matching features if ( mComposition->atlasMode() == QgsComposition::PreviewAtlas ) { firstFeature(); } return mFeatureIds.size(); }