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();
 
  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;
 
  238 class AtlasFeatureSorter
 
  241     AtlasFeatureSorter( QgsLayoutAtlas::SorterKeys &keys, 
bool ascending = 
true )
 
  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() )
 
  291 #ifdef HAVE_SERVER_PYTHON_PLUGINS 
  292   if ( mLayout->renderContext().featureFilterProvider() )
 
  294     mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.
get(), req );
 
  300   std::unique_ptr<QgsExpression> nameExpression;
 
  301   if ( !mPageNameExpression.isEmpty() )
 
  303     nameExpression = std::make_unique< QgsExpression >( mPageNameExpression );
 
  304     if ( nameExpression->hasParserError() )
 
  306       nameExpression.reset( 
nullptr );
 
  310       nameExpression->prepare( &expressionContext );
 
  318   mFeatureKeys.clear();
 
  321   if ( mSortFeatures && !mSortExpression.isEmpty() )
 
  323     sortExpression = std::make_unique< QgsExpression >( mSortExpression );
 
  339     if ( nameExpression )
 
  341       QVariant result = nameExpression->evaluate( &expressionContext );
 
  342       if ( nameExpression->hasEvalError() )
 
  346       pageName = result.toString();
 
  349     mFeatureIds.push_back( qMakePair( feat.
id(), pageName ) );
 
  358       mFeatureKeys.insert( feat.
id(), result );
 
  363   if ( !mFeatureKeys.isEmpty() )
 
  366     std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); 
 
  370   return mFeatureIds.size();
 
  375   if ( !mCoverageLayer )
 
  400   return mFeatureIds.size();
 
  405   QFileInfo fi( baseFilePath );
 
  407   QString base = dir.filePath( mCurrentFilename );
 
  408   if ( !extension.startsWith( 
'.' ) )
 
  416   int newFeatureNo = mCurrentFeatureNo + 1;
 
  417   if ( newFeatureNo >= mFeatureIds.size() )
 
  422   return prepareForFeature( newFeatureNo );
 
  427   int newFeatureNo = mCurrentFeatureNo - 1;
 
  428   if ( newFeatureNo < 0 )
 
  433   return prepareForFeature( newFeatureNo );
 
  438   return prepareForFeature( 0 );
 
  443   return prepareForFeature( mFeatureIds.size() - 1 );
 
  448   return prepareForFeature( feature );
 
  454   auto it = mFeatureIds.constBegin();
 
  455   for ( 
int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
 
  457     if ( ( *it ).first == feature.
id() )
 
  475   prepareForFeature( mCurrentFeatureNo );
 
  481   if ( hide == mHideCoverage )
 
  484   mHideCoverage = hide;
 
  491   const bool hasChanged = mFilenameExpressionString != pattern;
 
  492   mFilenameExpressionString = pattern;
 
  497   return updateFilenameExpression( errorString );
 
  502   return mCurrentFilename;
 
  515   if ( mCoverageLayer )
 
  518   if ( mLayout && mEnabled )
 
  520     if ( mCurrentFeature.
isValid() )
 
  524     else if ( mCoverageLayer )  
 
  527       feature.setValid( 
true );
 
  531   return expressionContext;
 
  534 bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
 
  536   if ( !mCoverageLayer )
 
  542   bool evalResult { 
true };
 
  544   if ( !mFilenameExpressionString.isEmpty() )
 
  562     evalResult = evalFeatureFilename( expressionContext );
 
  567     error = mFilenameExpressionError;
 
  576   mFilenameExpressionError.clear();
 
  577   if ( !mFilenameExpressionString.isEmpty() )
 
  589     mCurrentFilename = filenameRes.toString();
 
  594 bool QgsLayoutAtlas::prepareForFeature( 
const int featureI )
 
  596   if ( !mCoverageLayer )
 
  601   if ( mFeatureIds.isEmpty() )
 
  607   if ( featureI >= mFeatureIds.size() )
 
  612   mCurrentFeatureNo = featureI;
 
  618   mLayout->reportContext().blockSignals( 
true ); 
 
  619   mLayout->reportContext().setLayer( mCoverageLayer.
get() );
 
  620   mLayout->reportContext().blockSignals( 
false );
 
  621   mLayout->reportContext().setFeature( mCurrentFeature );
 
  627   if ( !evalFeatureFilename( expressionContext ) )
 
  634   emit 
messagePushed( tr( 
"Atlas feature %1 of %2" ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
 
  636   return mCurrentFeature.
isValid();
 
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.
Class for 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)
This class 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 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 toggled(bool)
Emitted when atlas is enabled or disabled.
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 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.
@ FlagHideCoverageLayer
Hide coverage layer in outputs.
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)
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.
The class is used as a container of context for various read/write operations on other objects.
Represents a vector layer which manages a vector based data sets.
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.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
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.
_LayerRef< QgsVectorLayer > QgsVectorLayerRef
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.
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.
void setLayer(TYPE *l)
Sets the reference to point to a specified layer.
QString layerId
Original layer ID.