QGIS API Documentation  3.23.0-Master (dd0cd13a00)
qgslayoutatlas.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutatlas.cpp
3  ----------------
4  begin : December 2017
5  copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include <algorithm>
18 #include <stdexcept>
19 #include <QtAlgorithms>
20 
21 #include "qgslayoutatlas.h"
22 #include "qgslayout.h"
23 #include "qgsmessagelog.h"
24 #include "qgsfeaturerequest.h"
25 #include "qgsfeatureiterator.h"
26 #include "qgsvectorlayer.h"
28 
30  : QObject( layout )
31  , mLayout( layout )
32  , mFilenameExpressionString( QStringLiteral( "'output_'||@atlas_featurenumber" ) )
33 {
34 
35  //listen out for layer removal
36  connect( mLayout->project(), static_cast < void ( QgsProject::* )( const QStringList & ) >( &QgsProject::layersWillBeRemoved ), this, &QgsLayoutAtlas::removeLayers );
37 
38  if ( mLayout->customProperty( QStringLiteral( "singleFile" ) ).isNull() )
39  mLayout->setCustomProperty( QStringLiteral( "singleFile" ), true );
40 }
41 
43 {
44  return QStringLiteral( "atlas" );
45 }
46 
48 {
49  return mLayout;
50 }
51 
53 {
54  return mLayout.data();
55 }
56 
57 bool QgsLayoutAtlas::writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext & ) const
58 {
59  QDomElement atlasElem = document.createElement( QStringLiteral( "Atlas" ) );
60  atlasElem.setAttribute( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
61 
62  if ( mCoverageLayer )
63  {
64  atlasElem.setAttribute( QStringLiteral( "coverageLayer" ), mCoverageLayer.layerId );
65  atlasElem.setAttribute( QStringLiteral( "coverageLayerName" ), mCoverageLayer.name );
66  atlasElem.setAttribute( QStringLiteral( "coverageLayerSource" ), mCoverageLayer.source );
67  atlasElem.setAttribute( QStringLiteral( "coverageLayerProvider" ), mCoverageLayer.provider );
68  }
69  else
70  {
71  atlasElem.setAttribute( QStringLiteral( "coverageLayer" ), QString() );
72  }
73 
74  atlasElem.setAttribute( QStringLiteral( "hideCoverage" ), mHideCoverage ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
75  atlasElem.setAttribute( QStringLiteral( "filenamePattern" ), mFilenameExpressionString );
76  atlasElem.setAttribute( QStringLiteral( "pageNameExpression" ), mPageNameExpression );
77 
78  atlasElem.setAttribute( QStringLiteral( "sortFeatures" ), mSortFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
79  if ( mSortFeatures )
80  {
81  atlasElem.setAttribute( QStringLiteral( "sortKey" ), mSortExpression );
82  atlasElem.setAttribute( QStringLiteral( "sortAscending" ), mSortAscending ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
83  }
84  atlasElem.setAttribute( QStringLiteral( "filterFeatures" ), mFilterFeatures ? QStringLiteral( "1" ) : QStringLiteral( "0" ) );
85  if ( mFilterFeatures )
86  {
87  atlasElem.setAttribute( QStringLiteral( "featureFilter" ), mFilterExpression );
88  }
89 
90  parentElement.appendChild( atlasElem );
91 
92  return true;
93 }
94 
95 bool QgsLayoutAtlas::readXml( const QDomElement &atlasElem, const QDomDocument &, const QgsReadWriteContext & )
96 {
97  mEnabled = atlasElem.attribute( QStringLiteral( "enabled" ), QStringLiteral( "0" ) ).toInt();
98 
99  // look for stored layer name
100  const QString layerId = atlasElem.attribute( QStringLiteral( "coverageLayer" ) );
101  const QString layerName = atlasElem.attribute( QStringLiteral( "coverageLayerName" ) );
102  const QString layerSource = atlasElem.attribute( QStringLiteral( "coverageLayerSource" ) );
103  const QString layerProvider = atlasElem.attribute( QStringLiteral( "coverageLayerProvider" ) );
104 
105  mCoverageLayer = QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
106  mCoverageLayer.resolveWeakly( mLayout->project() );
107  mLayout->reportContext().setLayer( mCoverageLayer.get() );
108 
109  mPageNameExpression = atlasElem.attribute( QStringLiteral( "pageNameExpression" ), QString() );
110  QString error;
111  setFilenameExpression( atlasElem.attribute( QStringLiteral( "filenamePattern" ), QString() ), error );
112 
113  mSortFeatures = atlasElem.attribute( QStringLiteral( "sortFeatures" ), QStringLiteral( "0" ) ).toInt();
114  mSortExpression = atlasElem.attribute( QStringLiteral( "sortKey" ) );
115  mSortAscending = atlasElem.attribute( QStringLiteral( "sortAscending" ), QStringLiteral( "1" ) ).toInt();
116  mFilterFeatures = atlasElem.attribute( QStringLiteral( "filterFeatures" ), QStringLiteral( "0" ) ).toInt();
117  mFilterExpression = atlasElem.attribute( QStringLiteral( "featureFilter" ) );
118 
119  mHideCoverage = atlasElem.attribute( QStringLiteral( "hideCoverage" ), QStringLiteral( "0" ) ).toInt();
120 
121  emit toggled( mEnabled );
122  emit changed();
123  return true;
124 }
125 
126 void QgsLayoutAtlas::setEnabled( bool enabled )
127 {
128  if ( enabled == mEnabled )
129  {
130  return;
131  }
132 
133  mEnabled = enabled;
134  emit toggled( enabled );
135  emit changed();
136 }
137 
138 void QgsLayoutAtlas::removeLayers( const QStringList &layers )
139 {
140  if ( !mCoverageLayer )
141  {
142  return;
143  }
144 
145  for ( const QString &layerId : layers )
146  {
147  if ( layerId == mCoverageLayer.layerId )
148  {
149  //current coverage layer removed
150  mCoverageLayer.setLayer( nullptr );
151  setEnabled( false );
152  break;
153  }
154  }
155 }
156 
158 {
159  if ( layer == mCoverageLayer.get() )
160  {
161  return;
162  }
163 
164  mCoverageLayer.setLayer( layer );
165  emit coverageLayerChanged( layer );
166 }
167 
168 void QgsLayoutAtlas::setPageNameExpression( const QString &expression )
169 {
170  if ( mPageNameExpression == expression )
171  return;
172 
173  mPageNameExpression = expression;
174  emit changed();
175 }
176 
177 QString QgsLayoutAtlas::nameForPage( int pageNumber ) const
178 {
179  if ( pageNumber < 0 || pageNumber >= mFeatureIds.count() )
180  return QString();
181 
182  return mFeatureIds.at( pageNumber ).second;
183 }
184 
186 {
187  if ( mSortFeatures == enabled )
188  return;
189 
190  mSortFeatures = enabled;
191  emit changed();
192 }
193 
194 void QgsLayoutAtlas::setSortAscending( bool ascending )
195 {
196  if ( mSortAscending == ascending )
197  return;
198 
199  mSortAscending = ascending;
200  emit changed();
201 }
202 
203 void QgsLayoutAtlas::setSortExpression( const QString &expression )
204 {
205  if ( mSortExpression == expression )
206  return;
207 
208  mSortExpression = expression;
209  emit changed();
210 }
211 
213 {
214  if ( mFilterFeatures == filtered )
215  return;
216 
217  mFilterFeatures = filtered;
218  emit changed();
219 }
220 
221 bool QgsLayoutAtlas::setFilterExpression( const QString &expression, QString &errorString )
222 {
223  errorString.clear();
224  const bool hasChanged = mFilterExpression != expression;
225  mFilterExpression = expression;
226 
227  const QgsExpression filterExpression( mFilterExpression );
228  if ( hasChanged )
229  emit changed();
230  if ( filterExpression.hasParserError() )
231  {
232  errorString = filterExpression.parserErrorString();
233  return false;
234  }
235 
236  return true;
237 }
238 
239 
241 class AtlasFeatureSorter
242 {
243  public:
244  AtlasFeatureSorter( QgsLayoutAtlas::SorterKeys &keys, bool ascending = true )
245  : mKeys( keys )
246  , mAscending( ascending )
247  {}
248 
249  bool operator()( const QPair< QgsFeatureId, QString > &id1, const QPair< QgsFeatureId, QString > &id2 )
250  {
251  return mAscending ? qgsVariantLessThan( mKeys.value( id1.first ), mKeys.value( id2.first ) )
252  : qgsVariantGreaterThan( mKeys.value( id1.first ), mKeys.value( id2.first ) );
253  }
254 
255  private:
256  QgsLayoutAtlas::SorterKeys &mKeys;
257  bool mAscending;
258 };
259 
261 
263 {
264  mCurrentFeatureNo = -1;
265  if ( !mCoverageLayer )
266  {
267  return 0;
268  }
269 
270  QgsExpressionContext expressionContext = createExpressionContext();
271 
272  QString error;
273  updateFilenameExpression( error );
274 
275  // select all features with all attributes
276  QgsFeatureRequest req;
277 
278  req.setExpressionContext( expressionContext );
279 
280  mFilterParserError.clear();
281  if ( mFilterFeatures && !mFilterExpression.isEmpty() )
282  {
283  const QgsExpression filterExpression( mFilterExpression );
284  if ( filterExpression.hasParserError() )
285  {
286  mFilterParserError = filterExpression.parserErrorString();
287  return 0;
288  }
289 
290  //filter good to go
291  req.setFilterExpression( mFilterExpression );
292  }
293 
294 #ifdef HAVE_SERVER_PYTHON_PLUGINS
295  if ( mLayout->renderContext().featureFilterProvider() )
296  {
297  mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.get(), req );
298  }
299 #endif
300 
301  QgsFeatureIterator fit = mCoverageLayer->getFeatures( req );
302 
303  std::unique_ptr<QgsExpression> nameExpression;
304  if ( !mPageNameExpression.isEmpty() )
305  {
306  nameExpression = std::make_unique< QgsExpression >( mPageNameExpression );
307  if ( nameExpression->hasParserError() )
308  {
309  nameExpression.reset( nullptr );
310  }
311  else
312  {
313  nameExpression->prepare( &expressionContext );
314  }
315  }
316 
317  // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process
318  // We thus store the feature ids for future extraction
319  QgsFeature feat;
320  mFeatureIds.clear();
321  mFeatureKeys.clear();
322 
323  std::unique_ptr<QgsExpression> sortExpression;
324  if ( mSortFeatures && !mSortExpression.isEmpty() )
325  {
326  sortExpression = std::make_unique< QgsExpression >( mSortExpression );
327  if ( sortExpression->hasParserError() )
328  {
329  sortExpression.reset( nullptr );
330  }
331  else
332  {
333  sortExpression->prepare( &expressionContext );
334  }
335  }
336 
337  while ( fit.nextFeature( feat ) )
338  {
339  expressionContext.setFeature( feat );
340 
341  QString pageName;
342  if ( nameExpression )
343  {
344  const QVariant result = nameExpression->evaluate( &expressionContext );
345  if ( nameExpression->hasEvalError() )
346  {
347  QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Layout" ) );
348  }
349  pageName = result.toString();
350  }
351 
352  mFeatureIds.push_back( qMakePair( feat.id(), pageName ) );
353 
354  if ( sortExpression )
355  {
356  const QVariant result = sortExpression->evaluate( &expressionContext );
357  if ( sortExpression->hasEvalError() )
358  {
359  QgsMessageLog::logMessage( tr( "Atlas sort eval error: %1" ).arg( sortExpression->evalErrorString() ), tr( "Layout" ) );
360  }
361  mFeatureKeys.insert( feat.id(), result );
362  }
363  }
364 
365  // sort features, if asked for
366  if ( !mFeatureKeys.isEmpty() )
367  {
368  const AtlasFeatureSorter sorter( mFeatureKeys, mSortAscending );
369  std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); // clazy:exclude=detaching-member
370  }
371 
372  emit numberFeaturesChanged( mFeatureIds.size() );
373  return mFeatureIds.size();
374 }
375 
377 {
378  if ( !mCoverageLayer )
379  {
380  return false;
381  }
382 
383  emit renderBegun();
384 
385  if ( !updateFeatures() )
386  {
387  //no matching features found
388  return false;
389  }
390 
391  return true;
392 }
393 
395 {
396  emit featureChanged( QgsFeature() );
397  emit renderEnded();
398  return true;
399 }
400 
402 {
403  return mFeatureIds.size();
404 }
405 
406 QString QgsLayoutAtlas::filePath( const QString &baseFilePath, const QString &extension )
407 {
408  const QFileInfo fi( baseFilePath );
409  const QDir dir = fi.dir(); // ignore everything except the directory
410  QString base = dir.filePath( mCurrentFilename );
411  if ( !extension.startsWith( '.' ) )
412  base += '.';
413  base += extension;
414  return base;
415 }
416 
418 {
419  const int newFeatureNo = mCurrentFeatureNo + 1;
420  if ( newFeatureNo >= mFeatureIds.size() )
421  {
422  return false;
423  }
424 
425  return prepareForFeature( newFeatureNo );
426 }
427 
429 {
430  const int newFeatureNo = mCurrentFeatureNo - 1;
431  if ( newFeatureNo < 0 )
432  {
433  return false;
434  }
435 
436  return prepareForFeature( newFeatureNo );
437 }
438 
440 {
441  return prepareForFeature( 0 );
442 }
443 
445 {
446  return prepareForFeature( mFeatureIds.size() - 1 );
447 }
448 
449 bool QgsLayoutAtlas::seekTo( int feature )
450 {
451  return prepareForFeature( feature );
452 }
453 
454 bool QgsLayoutAtlas::seekTo( const QgsFeature &feature )
455 {
456  int i = -1;
457  auto it = mFeatureIds.constBegin();
458  for ( int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
459  {
460  if ( ( *it ).first == feature.id() )
461  {
462  i = currentIdx;
463  break;
464  }
465  }
466 
467  if ( i < 0 )
468  {
469  //feature not found
470  return false;
471  }
472 
473  return seekTo( i );
474 }
475 
477 {
478  prepareForFeature( mCurrentFeatureNo );
479 }
480 
482 {
483  mLayout->renderContext().setFlag( QgsLayoutRenderContext::FlagHideCoverageLayer, hide );
484  if ( hide == mHideCoverage )
485  return;
486 
487  mHideCoverage = hide;
488  mLayout->refresh();
489  emit changed();
490 }
491 
492 bool QgsLayoutAtlas::setFilenameExpression( const QString &pattern, QString &errorString )
493 {
494  const bool hasChanged = mFilenameExpressionString != pattern;
495  mFilenameExpressionString = pattern;
496 
497  if ( hasChanged )
498  emit changed();
499 
500  return updateFilenameExpression( errorString );
501 }
502 
504 {
505  return mCurrentFilename;
506 }
507 
509 {
510  QgsExpressionContext expressionContext;
511  expressionContext << QgsExpressionContextUtils::globalScope();
512  if ( mLayout )
513  expressionContext << QgsExpressionContextUtils::projectScope( mLayout->project() )
515 
516  expressionContext.appendScope( QgsExpressionContextUtils::atlasScope( this ) );
517 
518  if ( mCoverageLayer )
519  expressionContext.appendScope( mCoverageLayer->createExpressionContextScope() );
520 
521  if ( mLayout && mEnabled )
522  {
523  if ( mCurrentFeature.isValid() )
524  {
525  expressionContext.lastScope()->setFeature( mCurrentFeature );
526  }
527  else if ( mCoverageLayer ) // Create an empty feature for the expression validation
528  {
529  QgsFeature feature{ mCoverageLayer->fields() };
530  feature.setValid( true );
531  expressionContext.lastScope()->setFeature( feature );
532  }
533  }
534  return expressionContext;
535 }
536 
537 bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
538 {
539  if ( !mCoverageLayer )
540  {
541  return false;
542  }
543 
544  const QgsExpressionContext expressionContext = createExpressionContext();
545  bool evalResult { true };
546 
547  if ( !mFilenameExpressionString.isEmpty() )
548  {
549  QgsExpression filenameExpression( mFilenameExpressionString );
550  // expression used to evaluate each filename
551  // test for evaluation errors
552  if ( filenameExpression.hasParserError() )
553  {
554  error = filenameExpression.parserErrorString();
555  return false;
556  }
557 
558  // prepare the filename expression
559  evalResult = filenameExpression.prepare( &expressionContext );
560  }
561 
562  // regenerate current filename
563  if ( evalResult )
564  {
565  evalResult = evalFeatureFilename( expressionContext );
566  }
567 
568  if ( ! evalResult )
569  {
570  error = mFilenameExpressionError;
571  }
572 
573  return evalResult;
574 }
575 
576 bool QgsLayoutAtlas::evalFeatureFilename( const QgsExpressionContext &context )
577 {
578  //generate filename for current atlas feature
579  mFilenameExpressionError.clear();
580  if ( !mFilenameExpressionString.isEmpty() )
581  {
582  QgsExpression filenameExpression( mFilenameExpressionString );
583  filenameExpression.prepare( &context );
584  const QVariant filenameRes = filenameExpression.evaluate( &context );
585  if ( filenameExpression.hasEvalError() )
586  {
587  mFilenameExpressionError = filenameExpression.evalErrorString();
588  QgsMessageLog::logMessage( tr( "Atlas filename evaluation error: %1" ).arg( filenameExpression.evalErrorString() ), tr( "Layout" ) );
589  return false;
590  }
591 
592  mCurrentFilename = filenameRes.toString();
593  }
594  return true;
595 }
596 
597 bool QgsLayoutAtlas::prepareForFeature( const int featureI )
598 {
599  if ( !mCoverageLayer )
600  {
601  return false;
602  }
603 
604  if ( mFeatureIds.isEmpty() )
605  {
606  emit messagePushed( tr( "No matching atlas features" ) );
607  return false;
608  }
609 
610  if ( featureI >= mFeatureIds.size() )
611  {
612  return false;
613  }
614 
615  mCurrentFeatureNo = featureI;
616 
617  // retrieve the next feature, based on its id
618  if ( !mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].first ) ).nextFeature( mCurrentFeature ) )
619  return false;
620 
621  mLayout->reportContext().blockSignals( true ); // setFeature emits changed, we don't want 2 signals
622  mLayout->reportContext().setLayer( mCoverageLayer.get() );
623  mLayout->reportContext().blockSignals( false );
624  mLayout->reportContext().setFeature( mCurrentFeature );
625 
626  // must come after we've set the report context feature, or the expression context will have an outdated atlas feature
627  const QgsExpressionContext expressionContext = createExpressionContext();
628 
629  // generate filename for current feature
630  if ( !evalFeatureFilename( expressionContext ) )
631  {
632  //error evaluating filename
633  return false;
634  }
635 
636  emit featureChanged( mCurrentFeature );
637  emit messagePushed( tr( "Atlas feature %1 of %2" ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
638 
639  return mCurrentFeature.isValid();
640 }
641 
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...
Definition: qgsfeature.h:56
bool isValid() const
Returns the validity of this feature.
Definition: qgsfeature.cpp:209
Q_GADGET QgsFeatureId id
Definition: qgsfeature.h:64
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.
bool next() override
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.
Definition: qgslayout.h:51
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,...
Definition: qgsproject.h:101
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.
Definition: qgis.cpp:127
bool qgsVariantGreaterThan(const QVariant &lhs, const QVariant &rhs)
Compares two QVariant values and returns whether the first is greater than the second.
Definition: qgis.cpp:195
_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.