19 #include <QtAlgorithms>    32   , mFilenameExpressionString( QStringLiteral( 
"'output_'||@atlas_featurenumber" ) )
    41   return QStringLiteral( 
"atlas" );
    51   return mLayout.data();
    56   QDomElement atlasElem = document.createElement( QStringLiteral( 
"Atlas" ) );
    57   atlasElem.setAttribute( QStringLiteral( 
"enabled" ), mEnabled ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
    61     atlasElem.setAttribute( QStringLiteral( 
"coverageLayer" ), mCoverageLayer.
layerId );
    62     atlasElem.setAttribute( QStringLiteral( 
"coverageLayerName" ), mCoverageLayer.
name );
    63     atlasElem.setAttribute( QStringLiteral( 
"coverageLayerSource" ), mCoverageLayer.
source );
    64     atlasElem.setAttribute( QStringLiteral( 
"coverageLayerProvider" ), mCoverageLayer.
provider );
    68     atlasElem.setAttribute( QStringLiteral( 
"coverageLayer" ), QString() );
    71   atlasElem.setAttribute( QStringLiteral( 
"hideCoverage" ), mHideCoverage ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
    72   atlasElem.setAttribute( QStringLiteral( 
"filenamePattern" ), mFilenameExpressionString );
    73   atlasElem.setAttribute( QStringLiteral( 
"pageNameExpression" ), mPageNameExpression );
    75   atlasElem.setAttribute( QStringLiteral( 
"sortFeatures" ), mSortFeatures ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
    78     atlasElem.setAttribute( QStringLiteral( 
"sortKey" ), mSortExpression );
    79     atlasElem.setAttribute( QStringLiteral( 
"sortAscending" ), mSortAscending ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
    81   atlasElem.setAttribute( QStringLiteral( 
"filterFeatures" ), mFilterFeatures ? QStringLiteral( 
"1" ) : QStringLiteral( 
"0" ) );
    82   if ( mFilterFeatures )
    84     atlasElem.setAttribute( QStringLiteral( 
"featureFilter" ), mFilterExpression );
    87   parentElement.appendChild( atlasElem );
    94   mEnabled = atlasElem.attribute( QStringLiteral( 
"enabled" ), QStringLiteral( 
"0" ) ).toInt();
    97   QString layerId = atlasElem.attribute( QStringLiteral( 
"coverageLayer" ) );
    98   QString layerName = atlasElem.attribute( QStringLiteral( 
"coverageLayerName" ) );
    99   QString layerSource = atlasElem.attribute( QStringLiteral( 
"coverageLayerSource" ) );
   100   QString layerProvider = atlasElem.attribute( QStringLiteral( 
"coverageLayerProvider" ) );
   102   mCoverageLayer = 
QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
   104   mLayout->reportContext().setLayer( mCoverageLayer.
get() );
   106   mPageNameExpression = atlasElem.attribute( QStringLiteral( 
"pageNameExpression" ), QString() );
   108   setFilenameExpression( atlasElem.attribute( QStringLiteral( 
"filenamePattern" ), QString() ), error );
   110   mSortFeatures = atlasElem.attribute( QStringLiteral( 
"sortFeatures" ), QStringLiteral( 
"0" ) ).toInt();
   111   mSortExpression = atlasElem.attribute( QStringLiteral( 
"sortKey" ) );
   112   mSortAscending = atlasElem.attribute( QStringLiteral( 
"sortAscending" ), QStringLiteral( 
"1" ) ).toInt();
   113   mFilterFeatures = atlasElem.attribute( QStringLiteral( 
"filterFeatures" ), QStringLiteral( 
"0" ) ).toInt();
   114   mFilterExpression = atlasElem.attribute( QStringLiteral( 
"featureFilter" ) );
   116   mHideCoverage = atlasElem.attribute( QStringLiteral( 
"hideCoverage" ), QStringLiteral( 
"0" ) ).toInt();
   125   if ( enabled == mEnabled )
   135 void QgsLayoutAtlas::removeLayers( 
const QStringList &layers )
   137   if ( !mCoverageLayer )
   142   for ( 
const QString &layerId : layers )
   144     if ( layerId == mCoverageLayer.
layerId )
   156   if ( layer == mCoverageLayer.
get() )
   167   if ( mPageNameExpression == expression )
   170   mPageNameExpression = expression;
   176   if ( pageNumber < 0 || pageNumber >= mFeatureIds.count() )
   179   return mFeatureIds.at( pageNumber ).second;
   184   if ( mSortFeatures == enabled )
   193   if ( mSortAscending == ascending )
   196   mSortAscending = ascending;
   202   if ( mSortExpression == expression )
   205   mSortExpression = expression;
   211   if ( mFilterFeatures == filtered )
   214   mFilterFeatures = filtered;
   221   const bool hasChanged = mFilterExpression != expression;
   222   mFilterExpression = expression;
   243       , mAscending( ascending )
   246     bool operator()( 
const QPair< QgsFeatureId, QString > &id1, 
const QPair< QgsFeatureId, QString > &id2 )
   248       return mAscending ? 
qgsVariantLessThan( mKeys.value( id1.first ), mKeys.value( id2.first ) )
   253     QgsLayoutAtlas::SorterKeys &mKeys;
   261   mCurrentFeatureNo = -1;
   262   if ( !mCoverageLayer )
   270   updateFilenameExpression( error );
   277   mFilterParserError.clear();
   278   if ( mFilterFeatures && !mFilterExpression.isEmpty() )
   293   std::unique_ptr<QgsExpression> nameExpression;
   294   if ( !mPageNameExpression.isEmpty() )
   296     nameExpression = qgis::make_unique< QgsExpression >( mPageNameExpression );
   297     if ( nameExpression->hasParserError() )
   299       nameExpression.reset( 
nullptr );
   303       nameExpression->prepare( &expressionContext );
   311   mFeatureKeys.clear();
   314   if ( mSortFeatures && !mSortExpression.isEmpty() )
   316     sortExpression = qgis::make_unique< QgsExpression >( mSortExpression );
   317     if ( sortExpression->hasParserError() )
   319       sortExpression.reset( 
nullptr );
   323       sortExpression->prepare( &expressionContext );
   332     if ( nameExpression )
   334       QVariant result = nameExpression->evaluate( &expressionContext );
   335       if ( nameExpression->hasEvalError() )
   339       pageName = result.toString();
   342     mFeatureIds.push_back( qMakePair( feat.
id(), pageName ) );
   344     if ( sortExpression )
   346       QVariant result = sortExpression->evaluate( &expressionContext );
   347       if ( sortExpression->hasEvalError() )
   351       mFeatureKeys.insert( feat.
id(), result );
   356   if ( !mFeatureKeys.isEmpty() )
   359     std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); 
   363   return mFeatureIds.size();
   368   if ( !mCoverageLayer )
   393   return mFeatureIds.size();
   398   QFileInfo fi( baseFilePath );
   400   QString base = dir.filePath( mCurrentFilename );
   401   if ( !extension.startsWith( 
'.' ) )
   409   int newFeatureNo = mCurrentFeatureNo + 1;
   410   if ( newFeatureNo >= mFeatureIds.size() )
   415   return prepareForFeature( newFeatureNo );
   420   int newFeatureNo = mCurrentFeatureNo - 1;
   421   if ( newFeatureNo < 0 )
   426   return prepareForFeature( newFeatureNo );
   431   return prepareForFeature( 0 );
   436   return prepareForFeature( mFeatureIds.size() - 1 );
   441   return prepareForFeature( feature );
   447   auto it = mFeatureIds.constBegin();
   448   for ( 
int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
   450     if ( ( *it ).first == feature.
id() )
   468   prepareForFeature( mCurrentFeatureNo );
   474   if ( hide == mHideCoverage )
   477   mHideCoverage = hide;
   484   const bool hasChanged = mFilenameExpressionString != pattern;
   485   mFilenameExpressionString = pattern;
   490   return updateFilenameExpression( errorString );
   495   return mCurrentFilename;
   508   if ( mCoverageLayer )
   509     expressionContext.
appendScope( mCoverageLayer->createExpressionContextScope() );
   511   if ( mLayout && mEnabled )
   514   return expressionContext;
   517 bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
   519   if ( !mCoverageLayer )
   526   if ( !mFilenameExpressionString.isEmpty() )
   528     mFilenameExpression = 
QgsExpression( mFilenameExpressionString );
   531     if ( mFilenameExpression.hasParserError() )
   533       error = mFilenameExpression.parserErrorString();
   538     mFilenameExpression.prepare( &expressionContext );
   542   evalFeatureFilename( expressionContext );
   549   if ( !mFilenameExpressionString.isEmpty() && mFilenameExpression.isValid() )
   551     QVariant filenameRes = mFilenameExpression.evaluate( &context );
   552     if ( mFilenameExpression.hasEvalError() )
   554       QgsMessageLog::logMessage( tr( 
"Atlas filename evaluation error: %1" ).arg( mFilenameExpression.evalErrorString() ), tr( 
"Layout" ) );
   558     mCurrentFilename = filenameRes.toString();
   563 bool QgsLayoutAtlas::prepareForFeature( 
const int featureI )
   565   if ( !mCoverageLayer )
   570   if ( mFeatureIds.isEmpty() )
   576   if ( featureI >= mFeatureIds.size() )
   581   mCurrentFeatureNo = featureI;
   584   if ( !mCoverageLayer->getFeatures( 
QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].
first ) ).nextFeature( mCurrentFeature ) )
   587   mLayout->reportContext().blockSignals( 
true ); 
   588   mLayout->reportContext().setLayer( mCoverageLayer.get() );
   589   mLayout->reportContext().blockSignals( 
false );
   590   mLayout->reportContext().setFeature( mCurrentFeature );
   596   if ( !evalFeatureFilename( expressionContext ) )
   603   emit 
messagePushed( QString( tr( 
"Atlas feature %1 of %2" ) ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
   605   return mCurrentFeature.isValid();
 void setCoverageLayer(QgsVectorLayer *layer)
Sets the coverage layer to use for the atlas features. 
 
Class for parsing and evaluation of expressions (formerly called "search strings"). 
 
bool hasParserError() const
Returns true if an error occurred when parsing the input expression. 
 
The class is used as a container of context for various read/write operations on other objects...
 
Wrapper for iterator of features from vector data provider or vector layer. 
 
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...
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context. 
 
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 sortExpression() const
Returns the expression (or field name) to use for sorting features. 
 
int count() const override
Returns the number of features to iterate over. 
 
void setSortAscending(bool ascending)
Sets whether features should be sorted in an ascending order. 
 
void setFilterFeatures(bool filtered)
Sets whether features should be filtered in the coverage layer. 
 
QString stringType() const override
Returns the object type as a string. 
 
void toggled(bool)
Emitted when atlas is enabled or disabled. 
 
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project. 
 
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
 
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second. 
 
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas. 
 
bool writeXml(QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context) const override
Stores the objects's state in a DOM element. 
 
QString parserErrorString() const
Returns parser error. 
 
void setSortExpression(const QString &expression)
Sets the expression (or field name) to use for sorting features. 
 
bool qgsVariantLessThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is less than the second. 
 
QgsLayoutAtlas(QgsLayout *layout)
Constructor for new QgsLayoutAtlas. 
 
QgsLayout * layout() override
Returns the layout associated with the iterator. 
 
bool endRender() override
Ends the render, performing any required cleanup tasks. 
 
bool setFilenameExpression(const QString &expression, QString &errorString)
Sets the filename expression used for generating output filenames for each atlas page. 
 
QgsFeatureRequest & setExpressionContext(const QgsExpressionContext &context)
Sets the expression context used to evaluate filter expressions. 
 
void refreshCurrentFeature()
Refreshes the current atlas feature, by refetching its attributes from the vector layer provider...
 
void numberFeaturesChanged(int numFeatures)
Emitted when the number of features for the atlas changes. 
 
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context. 
 
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression. 
 
QString provider
Weak reference to layer provider. 
 
QString layerId
Original layer ID. 
 
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
 
bool readXml(const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context) override
Sets the objects's state from a DOM element. 
 
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
 
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary). 
 
QString name
Weak reference to layer name. 
 
bool last()
Seeks to the last feature, returning false if no feature was found. 
 
This class wraps a request for features to a vector layer (or directly its vector data provider)...
 
Hide coverage layer in outputs. 
 
Encapsulates a QGIS project, including sets of map layers and their styles, layouts, annotations, canvases, etc. 
 
QString currentFilename() const
Returns the current feature filename. 
 
void setHideCoverage(bool hide)
Sets whether the coverage layer should be hidden in map items in the layouts. 
 
bool first()
Seeks to the first feature, returning false if no feature was found. 
 
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the scope. 
 
void setLayer(TYPE *l)
Sets the reference to point to a specified layer. 
 
void renderBegun()
Emitted when atlas rendering has begun. 
 
QString source
Weak reference to layer public source. 
 
Base class for layouts, which can contain items such as maps, labels, scalebars, etc. 
 
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
 
bool previous()
Iterates to the previous feature, returning false if no previous feature exists. 
 
QString filterExpression() const
Returns the expression used for filtering features in the coverage layer. 
 
bool setFilterExpression(const QString &expression, QString &errorString)
Sets the expression used for filtering features in the coverage layer. 
 
void renderEnded()
Emitted when atlas rendering has ended. 
 
void layersWillBeRemoved(const QStringList &layerIds)
Emitted when one or more layers are about to be removed from the registry. 
 
static QgsExpressionContextScope * layoutScope(const QgsLayout *layout)
Creates a new scope which contains variables and functions relating to a QgsLayout layout...
 
void setEnabled(bool enabled)
Sets whether the atlas is enabled. 
 
friend class AtlasFeatureSorter
 
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context. 
 
void featureChanged(const QgsFeature &feature)
Emitted when the current atlas feature changes. 
 
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
 
int updateFeatures()
Requeries the current atlas coverage layer and applies filtering and sorting. 
 
QString nameForPage(int page) const
Returns the calculated name for a specified atlas page number. 
 
bool enabled() const
Returns whether the atlas generation is enabled. 
 
bool beginRender() override
Called when rendering begins, before iteration commences. 
 
void messagePushed(const QString &message)
Emitted when the atlas has an updated status bar message. 
 
void setSortFeatures(bool enabled)
Sets whether features should be sorted in the atlas. 
 
bool nextFeature(QgsFeature &f)
 
void setPageNameExpression(const QString &expression)
Sets the expression (or field name) used for calculating the page name. 
 
Represents a vector layer which manages a vector based data sets. 
 
TYPE * get() const
Returns a pointer to the layer, or nullptr if the reference has not yet been matched to a layer...
 
void changed()
Emitted when one of the atlas parameters changes. 
 
bool seekTo(int feature)
Seeks to the specified feature number. 
 
void coverageLayerChanged(QgsVectorLayer *layer)
Emitted when the coverage layer for the atlas changes.