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