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