Example #1
0
void QgsAtlasComposition::setFilenamePattern( const QString& pattern )
{
  mFilenamePattern = pattern;
  updateFilenameExpression();
}
Example #2
0
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();
}
Example #3
0
bool QgsLayoutAtlas::setFilenameExpression( const QString &pattern, QString &errorString )
{
  mFilenameExpressionString = pattern;
  return updateFilenameExpression( errorString );
}
Example #4
0
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();
}
Example #5
0
int QgsLayoutAtlas::updateFeatures()
{
  mCurrentFeatureNo = -1;
  if ( !mCoverageLayer )
  {
    return 0;
  }

  QgsExpressionContext expressionContext = createExpressionContext();

  QString error;
  updateFilenameExpression( error );

  // select all features with all attributes
  QgsFeatureRequest req;

  req.setExpressionContext( expressionContext );

  mFilterParserError.clear();
  if ( mFilterFeatures && !mFilterExpression.isEmpty() )
  {
    QgsExpression filterExpression( mFilterExpression );
    if ( filterExpression.hasParserError() )
    {
      mFilterParserError = filterExpression.parserErrorString();
      return 0;
    }

    //filter good to go
    req.setFilterExpression( mFilterExpression );
  }

  QgsFeatureIterator fit = mCoverageLayer->getFeatures( req );

  std::unique_ptr<QgsExpression> nameExpression;
  if ( !mPageNameExpression.isEmpty() )
  {
    nameExpression = qgis::make_unique< 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();

  std::unique_ptr<QgsExpression> sortExpression;
  if ( mSortFeatures && !mSortExpression.isEmpty() )
  {
    sortExpression = qgis::make_unique< QgsExpression >( mSortExpression );
    if ( sortExpression->hasParserError() )
    {
      sortExpression.reset( nullptr );
    }
    else
    {
      sortExpression->prepare( &expressionContext );
    }
  }

  while ( fit.nextFeature( feat ) )
  {
    expressionContext.setFeature( feat );

    QString pageName;
    if ( nameExpression )
    {
      QVariant result = nameExpression->evaluate( &expressionContext );
      if ( nameExpression->hasEvalError() )
      {
        QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Layout" ) );
      }
      pageName = result.toString();
    }

    mFeatureIds.push_back( qMakePair( feat.id(), pageName ) );

    if ( sortExpression )
    {
      QVariant result = sortExpression->evaluate( &expressionContext );
      if ( sortExpression->hasEvalError() )
      {
        QgsMessageLog::logMessage( tr( "Atlas sort eval error: %1" ).arg( sortExpression->evalErrorString() ), tr( "Layout" ) );
      }
      mFeatureKeys.insert( feat.id(), result );
    }
  }

  // sort features, if asked for
  if ( !mFeatureKeys.isEmpty() )
  {
    AtlasFeatureSorter sorter( mFeatureKeys, mSortAscending );
    std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); // clazy:exclude=detaching-member
  }

  emit numberFeaturesChanged( mFeatureIds.size() );
  return mFeatureIds.size();
}