19#include <QtAlgorithms> 
   22#include "moc_qgslayoutatlas.cpp" 
   36  , mFilenameExpressionString( QStringLiteral( 
"'output_'||@atlas_featurenumber" ) )
 
   43    mLayout->setCustomProperty( QStringLiteral( 
"singleFile" ), 
true );
 
 
   48  return QStringLiteral( 
"atlas" );
 
 
   58  return mLayout.data();
 
 
   63  QDomElement atlasElem = document.createElement( QStringLiteral( 
"Atlas" ) );
 
   64  atlasElem.setAttribute( QStringLiteral( 
"enabled" ), mEnabled ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   68    atlasElem.setAttribute( QStringLiteral( 
"coverageLayer" ), mCoverageLayer.
layerId );
 
   69    atlasElem.setAttribute( QStringLiteral( 
"coverageLayerName" ), mCoverageLayer.
name );
 
   70    atlasElem.setAttribute( QStringLiteral( 
"coverageLayerSource" ), mCoverageLayer.
source );
 
   71    atlasElem.setAttribute( QStringLiteral( 
"coverageLayerProvider" ), mCoverageLayer.
provider );
 
   75    atlasElem.setAttribute( QStringLiteral( 
"coverageLayer" ), QString() );
 
   78  atlasElem.setAttribute( QStringLiteral( 
"limitCoverageLayerRenderToCurrentFeature" ), mLimitCoverageLayerRenderToCurrentFeature ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   79  atlasElem.setAttribute( QStringLiteral( 
"hideCoverage" ), mHideCoverage ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   80  atlasElem.setAttribute( QStringLiteral( 
"filenamePattern" ), mFilenameExpressionString );
 
   81  atlasElem.setAttribute( QStringLiteral( 
"pageNameExpression" ), mPageNameExpression );
 
   83  atlasElem.setAttribute( QStringLiteral( 
"sortFeatures" ), mSortFeatures ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   86    atlasElem.setAttribute( QStringLiteral( 
"sortKey" ), mSortExpression );
 
   87    atlasElem.setAttribute( QStringLiteral( 
"sortAscending" ), mSortAscending ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   89  atlasElem.setAttribute( QStringLiteral( 
"filterFeatures" ), mFilterFeatures ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
 
   90  if ( mFilterFeatures )
 
   92    atlasElem.setAttribute( QStringLiteral( 
"featureFilter" ), mFilterExpression );
 
   95  parentElement.appendChild( atlasElem );
 
 
  102  mEnabled = atlasElem.attribute( QStringLiteral( 
"enabled" ), QStringLiteral( 
"0" ) ).toInt();
 
  105  const QString layerId = atlasElem.attribute( QStringLiteral( 
"coverageLayer" ) );
 
  106  const QString layerName = atlasElem.attribute( QStringLiteral( 
"coverageLayerName" ) );
 
  107  const QString layerSource = atlasElem.attribute( QStringLiteral( 
"coverageLayerSource" ) );
 
  108  const QString layerProvider = atlasElem.attribute( QStringLiteral( 
"coverageLayerProvider" ) );
 
  110  mCoverageLayer = 
QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
 
  112  mLayout->reportContext().setLayer( mCoverageLayer.
get() );
 
  114  mPageNameExpression = atlasElem.attribute( QStringLiteral( 
"pageNameExpression" ), QString() );
 
  116  setFilenameExpression( atlasElem.attribute( QStringLiteral( 
"filenamePattern" ), QString() ), error );
 
  118  mSortFeatures = atlasElem.attribute( QStringLiteral( 
"sortFeatures" ), QStringLiteral( 
"0" ) ).toInt();
 
  119  mSortExpression = atlasElem.attribute( QStringLiteral( 
"sortKey" ) );
 
  120  mSortAscending = atlasElem.attribute( QStringLiteral( 
"sortAscending" ), QStringLiteral( 
"1" ) ).toInt();
 
  121  mFilterFeatures = atlasElem.attribute( QStringLiteral( 
"filterFeatures" ), QStringLiteral( 
"0" ) ).toInt();
 
  122  mFilterExpression = atlasElem.attribute( QStringLiteral( 
"featureFilter" ) );
 
  124  mLimitCoverageLayerRenderToCurrentFeature = atlasElem.attribute( QStringLiteral( 
"limitCoverageLayerRenderToCurrentFeature" ), QStringLiteral( 
"0" ) ).toInt();
 
  126  mHideCoverage = atlasElem.attribute( QStringLiteral( 
"hideCoverage" ), QStringLiteral( 
"0" ) ).toInt();
 
 
  146void QgsLayoutAtlas::removeLayers( 
const QStringList &layers )
 
  148  if ( !mCoverageLayer )
 
  153  for ( 
const QString &layerId : layers )
 
  155    if ( layerId == mCoverageLayer.
layerId )
 
  167  if ( layer == mCoverageLayer.
get() )
 
 
  178  if ( mPageNameExpression == expression )
 
  181  mPageNameExpression = expression;
 
 
  187  if ( pageNumber < 0 || pageNumber >= mFeatureIds.count() )
 
  190  return mFeatureIds.at( pageNumber ).second;
 
 
  195  if ( mSortFeatures == 
enabled )
 
 
  204  if ( mSortAscending == ascending )
 
  207  mSortAscending = ascending;
 
 
  213  if ( mSortExpression == expression )
 
  216  mSortExpression = expression;
 
 
  222  if ( mFilterFeatures == filtered )
 
  225  mFilterFeatures = filtered;
 
 
  232  const bool hasChanged = mFilterExpression != expression;
 
  233  mFilterExpression = expression;
 
 
  249class AtlasFeatureSorter
 
  252    AtlasFeatureSorter( QgsLayoutAtlas::SorterKeys &keys, 
bool ascending = 
true )
 
  254      , mAscending( ascending )
 
  257    bool operator()( 
const QPair< QgsFeatureId, QString > &id1, 
const QPair< QgsFeatureId, QString > &id2 )
 
  259      return mAscending ? 
qgsVariantLessThan( mKeys.value( id1.first ), mKeys.value( id2.first ) )
 
  264    QgsLayoutAtlas::SorterKeys &mKeys;
 
  272  mCurrentFeatureNo = -1;
 
  273  if ( !mCoverageLayer )
 
  281  updateFilenameExpression( error );
 
  288  mFilterParserError.clear();
 
  289  if ( mFilterFeatures && !mFilterExpression.isEmpty() )
 
  302#ifdef HAVE_SERVER_PYTHON_PLUGINS 
  303  if ( mLayout->renderContext().featureFilterProvider() )
 
  307    if ( mLayout->renderContext().featureFilterProvider()->isFilterThreadSafe() )
 
  309      mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.
get()->
id(), req );
 
  313      mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.
get(), req );
 
  322  std::unique_ptr<QgsExpression> nameExpression;
 
  323  if ( !mPageNameExpression.isEmpty() )
 
  325    nameExpression = std::make_unique< QgsExpression >( mPageNameExpression );
 
  326    if ( nameExpression->hasParserError() )
 
  328      nameExpression.reset( 
nullptr );
 
  332      nameExpression->prepare( &expressionContext );
 
  340  mFeatureKeys.clear();
 
  343  if ( mSortFeatures && !mSortExpression.isEmpty() )
 
  345    sortExpression = std::make_unique< QgsExpression >( mSortExpression );
 
  361    if ( nameExpression )
 
  363      const QVariant result = nameExpression->evaluate( &expressionContext );
 
  364      if ( nameExpression->hasEvalError() )
 
  368      pageName = result.toString();
 
  371    mFeatureIds.push_back( qMakePair( feat.
id(), pageName ) );
 
  375      const QVariant result = 
sortExpression->evaluate( &expressionContext );
 
  380      mFeatureKeys.insert( feat.
id(), result );
 
  385  if ( !mFeatureKeys.isEmpty() )
 
  388    std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); 
 
  392  return mFeatureIds.size();
 
 
  397  if ( !mCoverageLayer )
 
 
  422  return mFeatureIds.size();
 
 
  427  const QFileInfo fi( baseFilePath );
 
  428  const QDir dir = fi.dir(); 
 
  429  QString base = dir.filePath( mCurrentFilename );
 
  430  if ( !extension.startsWith( 
'.' ) )
 
 
  438  const int newFeatureNo = mCurrentFeatureNo + 1;
 
  439  if ( newFeatureNo >= mFeatureIds.size() )
 
  444  return prepareForFeature( newFeatureNo );
 
 
  449  const int newFeatureNo = mCurrentFeatureNo - 1;
 
  450  if ( newFeatureNo < 0 )
 
  455  return prepareForFeature( newFeatureNo );
 
 
  460  return prepareForFeature( 0 );
 
 
  465  return prepareForFeature( mFeatureIds.size() - 1 );
 
 
  470  return prepareForFeature( feature );
 
 
  476  auto it = mFeatureIds.constBegin();
 
  477  for ( 
int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
 
  479    if ( ( *it ).first == feature.
id() )
 
 
  497  prepareForFeature( mCurrentFeatureNo );
 
 
  503  if ( hide == mHideCoverage )
 
  506  mHideCoverage = hide;
 
 
  514  if ( limit == mLimitCoverageLayerRenderToCurrentFeature )
 
  517  mLimitCoverageLayerRenderToCurrentFeature = limit;
 
 
  524  const bool hasChanged = mFilenameExpressionString != pattern;
 
  525  mFilenameExpressionString = pattern;
 
  530  return updateFilenameExpression( errorString );
 
 
  535  return mCurrentFilename;
 
 
  548  if ( mCoverageLayer )
 
  551  if ( mLayout && mEnabled )
 
  553    if ( mCurrentFeature.
isValid() )
 
  557    else if ( mCoverageLayer )  
 
  560      feature.setValid( 
true );
 
  564  return expressionContext;
 
 
  567bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
 
  569  if ( !mCoverageLayer )
 
  575  bool evalResult { 
true };
 
  577  if ( !mFilenameExpressionString.isEmpty() )
 
  595    evalResult = evalFeatureFilename( expressionContext );
 
  600    error = mFilenameExpressionError;
 
  609  mFilenameExpressionError.clear();
 
  610  if ( !mFilenameExpressionString.isEmpty() )
 
  622    mCurrentFilename = filenameRes.toString();
 
  627bool QgsLayoutAtlas::prepareForFeature( 
const int featureI )
 
  629  if ( !mCoverageLayer )
 
  634  if ( mFeatureIds.isEmpty() )
 
  640  if ( featureI >= mFeatureIds.size() )
 
  645  mCurrentFeatureNo = featureI;
 
  651  mLayout->reportContext().blockSignals( 
true ); 
 
  652  mLayout->reportContext().setLayer( mCoverageLayer.
get() );
 
  653  mLayout->reportContext().blockSignals( 
false );
 
  654  mLayout->reportContext().setFeature( mCurrentFeature );
 
  660  if ( !evalFeatureFilename( expressionContext ) )
 
  667  emit 
messagePushed( tr( 
"Atlas feature %1 of %2" ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
 
  669  return mCurrentFeature.
isValid();
 
@ LimitCoverageLayerRenderToCurrentFeature
Limit coverage layer rendering to the current atlas feature.
 
@ HideCoverageLayer
Hide coverage layer in outputs.
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope.
 
static QgsExpressionContextScope * layoutScope(const QgsLayout *layout)
Creates a new scope which contains variables and functions relating to a QgsLayout layout.
 
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
 
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
 
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
 
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
 
Handles parsing and evaluation of expressions (formerly called "search strings").
 
Wrapper for iterator of features from vector data provider or vector layer.
 
bool nextFeature(QgsFeature &f)
Fetch next feature and stores in f, returns true on success.
 
Wraps a request for features to a vector layer (or directly its vector data provider).
 
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
 
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions.
 
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
 
bool isValid() const
Returns the validity of this feature.
 
QString nameForPage(int page) const
Returns the calculated name for a specified atlas page number.
 
QString sortExpression() const
Returns the expression (or field name) to use for sorting features.
 
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores the objects's state in a DOM element.
 
QString filenameExpression() const
Returns the filename expression used for generating output filenames for each atlas page.
 
void toggled(bool enabled)
Emitted when atlas is enabled or disabled.
 
void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features.
 
bool beginRender() override
Called when rendering begins, before iteration commences.
 
bool setFilterExpression(const QString &expression, QString &errorString)
Sets the expression used for filtering features in the coverage layer.
 
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order.
 
bool seekTo(int feature)
Seeks to the specified feature number.
 
void featureChanged(const QgsFeature &feature)
Emitted when the current atlas feature changes.
 
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
 
friend class AtlasFeatureSorter
 
void setPageNameExpression(const QString &expression)
Sets the expression (or field name) used for calculating the page name.
 
bool first()
Seeks to the first feature, returning false if no feature was found.
 
QString filterExpression() const
Returns the expression used for filtering features in the coverage layer.
 
QgsLayout * layout() override
Returns the layout associated with the iterator.
 
bool enabled() const
Returns whether the atlas generation is enabled.
 
bool setFilenameExpression(const QString &expression, QString &errorString)
Sets the filename expression used for generating output filenames for each atlas page.
 
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
 
void setLimitCoverageLayerRenderToCurrentFeature(bool limit)
Sets whether the rendering of the coverage layer should be limited to the current feature.
 
void setSortFeatures(bool enabled)
Sets whether features should be sorted in the atlas.
 
QString filePath(const QString &baseFilePath, const QString &extension) override
Returns the file path for the current feature, based on a specified base file path and extension.
 
QString currentFilename() const
Returns the current feature filename.
 
bool readXml(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets the objects's state from a DOM element.
 
bool last()
Seeks to the last feature, returning false if no feature was found.
 
QgsLayoutAtlas(QgsLayout *layout)
Constructor for new QgsLayoutAtlas.
 
int count() const override
Returns the number of features to iterate over.
 
void numberFeaturesChanged(int numFeatures)
Emitted when the number of features for the atlas changes.
 
void messagePushed(const QString &message)
Emitted when the atlas has an updated status bar message.
 
void setSortExpression(const QString &expression)
Sets the expression (or field name) to use for sorting features.
 
void coverageLayerChanged(QgsVectorLayer *layer)
Emitted when the coverage layer for the atlas changes.
 
void setFilterFeatures(bool filtered)
Sets whether features should be filtered in the coverage layer.
 
void renderBegun()
Emitted when atlas rendering has begun.
 
void renderEnded()
Emitted when atlas rendering has ended.
 
void changed()
Emitted when one of the atlas parameters changes.
 
bool previous()
Iterates to the previous feature, returning false if no previous feature exists.
 
void refreshCurrentFeature()
Refreshes the current atlas feature, by refetching its attributes from the vector layer provider.
 
bool endRender() override
Ends the render, performing any required cleanup tasks.
 
int updateFeatures()
Requeries the current atlas coverage layer and applies filtering and sorting.
 
QString stringType() const override
Returns the object type as a string.
 
void setHideCoverage(bool hide)
Sets whether the coverage layer should be hidden in map items in the layouts.
 
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true, const char *file=__builtin_FILE(), const char *function=__builtin_FUNCTION(), int line=__builtin_LINE())
Adds a message to the log instance (and creates it if necessary).
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
 
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry.
 
A container for the context for various read/write operations on objects.
 
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
 
Represents a vector layer which manages a vector based dataset.
 
QgsExpressionContextScope * createExpressionContextScope() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
 
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
 
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second.
 
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
 
#define Q_NOWARN_DEPRECATED_POP
 
#define Q_NOWARN_DEPRECATED_PUSH
 
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
 
TYPE * resolveWeakly(const QgsProject *project, MatchType matchType=MatchType::All)
Resolves the map layer by attempting to find a matching layer in a project using a weak match.
 
QString source
Weak reference to layer public source.
 
QString name
Weak reference to layer name.
 
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer.
 
QString provider
Weak reference to layer provider.
 
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
 
QString layerId
Original layer ID.