QGIS API Documentation 3.99.0-Master (d270888f95f)
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 {
313 // NOLINTBEGIN(bugprone-branch-clone)
315 if ( mLayout->renderContext().featureFilterProvider()->isFilterThreadSafe() )
316 {
317 mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.get()->id(), req );
318 }
319 else
320 {
321 mLayout->renderContext().featureFilterProvider()->filterFeatures( mCoverageLayer.get(), req );
322 }
324 // NOLINTEND(bugprone-branch-clone)
325 }
326#endif
327
328 QgsFeatureIterator fit = mCoverageLayer->getFeatures( req );
329
330 std::unique_ptr<QgsExpression> nameExpression;
331 if ( !mPageNameExpression.isEmpty() )
332 {
333 nameExpression = std::make_unique< QgsExpression >( mPageNameExpression );
334 if ( nameExpression->hasParserError() )
335 {
336 nameExpression.reset( nullptr );
337 }
338 else
339 {
340 nameExpression->prepare( &expressionContext );
341 }
342 }
343
344 // We cannot use nextFeature() directly since the feature pointer is rewinded by the rendering process
345 // We thus store the feature ids for future extraction
346 QgsFeature feat;
347 mFeatureIds.clear();
348 mFeatureKeys.clear();
349
350 std::unique_ptr<QgsExpression> sortExpression;
351 if ( mSortFeatures && !mSortExpression.isEmpty() )
352 {
353 sortExpression = std::make_unique< QgsExpression >( mSortExpression );
354 if ( sortExpression->hasParserError() )
355 {
356 sortExpression.reset( nullptr );
357 }
358 else
359 {
360 sortExpression->prepare( &expressionContext );
361 }
362 }
363
364 while ( fit.nextFeature( feat ) )
365 {
366 expressionContext.setFeature( feat );
367
368 QString pageName;
369 if ( nameExpression )
370 {
371 const QVariant result = nameExpression->evaluate( &expressionContext );
372 if ( nameExpression->hasEvalError() )
373 {
374 QgsMessageLog::logMessage( tr( "Atlas name eval error: %1" ).arg( nameExpression->evalErrorString() ), tr( "Layout" ) );
375 }
376 pageName = result.toString();
377 }
378
379 mFeatureIds.push_back( qMakePair( feat.id(), pageName ) );
380
381 if ( sortExpression )
382 {
383 const QVariant result = sortExpression->evaluate( &expressionContext );
384 if ( sortExpression->hasEvalError() )
385 {
386 QgsMessageLog::logMessage( tr( "Atlas sort eval error: %1" ).arg( sortExpression->evalErrorString() ), tr( "Layout" ) );
387 }
388 mFeatureKeys.insert( feat.id(), result );
389 }
390 }
391
392 // sort features, if asked for
393 if ( !mFeatureKeys.isEmpty() )
394 {
395 const AtlasFeatureSorter sorter( mFeatureKeys, mSortAscending );
396 std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); // clazy:exclude=detaching-member
397 }
398
399 emit numberFeaturesChanged( mFeatureIds.size() );
400 return mFeatureIds.size();
401}
402
404{
405 if ( !mCoverageLayer )
406 {
407 return false;
408 }
409
410 emit renderBegun();
411
412 if ( !updateFeatures() )
413 {
414 //no matching features found
415 return false;
416 }
417
418 return true;
419}
420
422{
423 emit featureChanged( QgsFeature() );
424 emit renderEnded();
425 return true;
426}
427
429{
430 return mFeatureIds.size();
431}
432
433QString QgsLayoutAtlas::filePath( const QString &baseFilePath, const QString &extension )
434{
435 const QFileInfo fi( baseFilePath );
436 const QDir dir = fi.dir(); // ignore everything except the directory
437 QString base = dir.filePath( mCurrentFilename );
438 if ( !extension.startsWith( '.' ) )
439 base += '.';
440 base += extension;
441 return base;
442}
443
445{
446 const int newFeatureNo = mCurrentFeatureNo + 1;
447 if ( newFeatureNo >= mFeatureIds.size() )
448 {
449 return false;
450 }
451
452 return prepareForFeature( newFeatureNo );
453}
454
456{
457 const int newFeatureNo = mCurrentFeatureNo - 1;
458 if ( newFeatureNo < 0 )
459 {
460 return false;
461 }
462
463 return prepareForFeature( newFeatureNo );
464}
465
467{
468 return prepareForFeature( 0 );
469}
470
472{
473 return prepareForFeature( mFeatureIds.size() - 1 );
474}
475
476bool QgsLayoutAtlas::seekTo( int feature )
477{
478 return prepareForFeature( feature );
479}
480
481bool QgsLayoutAtlas::seekTo( const QgsFeature &feature )
482{
483 int i = -1;
484 auto it = mFeatureIds.constBegin();
485 for ( int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
486 {
487 if ( ( *it ).first == feature.id() )
488 {
489 i = currentIdx;
490 break;
491 }
492 }
493
494 if ( i < 0 )
495 {
496 //feature not found
497 return false;
498 }
499
500 return seekTo( i );
501}
502
504{
505 prepareForFeature( mCurrentFeatureNo );
506}
507
509{
510 mLayout->renderContext().setFlag( Qgis::LayoutRenderFlag::HideCoverageLayer, hide );
511 if ( hide == mHideCoverage )
512 return;
513
514 mHideCoverage = hide;
515 mLayout->refresh();
516 emit changed();
517}
518
520{
521 mLayout->renderContext().setFlag( Qgis::LayoutRenderFlag::LimitCoverageLayerRenderToCurrentFeature, limit );
522 if ( limit == mLimitCoverageLayerRenderToCurrentFeature )
523 return;
524
525 mLimitCoverageLayerRenderToCurrentFeature = limit;
526 mLayout->refresh();
527 emit changed();
528}
529
530bool QgsLayoutAtlas::setFilenameExpression( const QString &pattern, QString &errorString )
531{
532 const bool hasChanged = mFilenameExpressionString != pattern;
533 mFilenameExpressionString = pattern;
534
535 if ( hasChanged )
536 emit changed();
537
538 return updateFilenameExpression( errorString );
539}
540
542{
543 return mCurrentFilename;
544}
545
547{
548 QgsExpressionContext expressionContext;
549 expressionContext << QgsExpressionContextUtils::globalScope();
550 if ( mLayout )
551 expressionContext << QgsExpressionContextUtils::projectScope( mLayout->project() )
553
554 expressionContext.appendScope( QgsExpressionContextUtils::atlasScope( this ) );
555
556 if ( mCoverageLayer )
557 expressionContext.appendScope( mCoverageLayer->createExpressionContextScope() );
558
559 if ( mLayout && mEnabled )
560 {
561 if ( mCurrentFeature.isValid() )
562 {
563 expressionContext.lastScope()->setFeature( mCurrentFeature );
564 }
565 else if ( mCoverageLayer ) // Create an empty feature for the expression validation
566 {
567 QgsFeature feature{ mCoverageLayer->fields() };
568 feature.setValid( true );
569 expressionContext.lastScope()->setFeature( feature );
570 }
571 }
572 return expressionContext;
573}
574
575bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
576{
577 if ( !mCoverageLayer )
578 {
579 return false;
580 }
581
582 const QgsExpressionContext expressionContext = createExpressionContext();
583 bool evalResult { true };
584
585 if ( !mFilenameExpressionString.isEmpty() )
586 {
587 QgsExpression filenameExpression( mFilenameExpressionString );
588 // expression used to evaluate each filename
589 // test for evaluation errors
590 if ( filenameExpression.hasParserError() )
591 {
592 error = filenameExpression.parserErrorString();
593 return false;
594 }
595
596 // prepare the filename expression
597 evalResult = filenameExpression.prepare( &expressionContext );
598 }
599
600 // regenerate current filename
601 if ( evalResult )
602 {
603 evalResult = evalFeatureFilename( expressionContext );
604 }
605
606 if ( ! evalResult )
607 {
608 error = mFilenameExpressionError;
609 }
610
611 return evalResult;
612}
613
614bool QgsLayoutAtlas::evalFeatureFilename( const QgsExpressionContext &context )
615{
616 //generate filename for current atlas feature
617 mFilenameExpressionError.clear();
618 if ( !mFilenameExpressionString.isEmpty() )
619 {
620 QgsExpression filenameExpression( mFilenameExpressionString );
621 filenameExpression.prepare( &context );
622 const QVariant filenameRes = filenameExpression.evaluate( &context );
623 if ( filenameExpression.hasEvalError() )
624 {
625 mFilenameExpressionError = filenameExpression.evalErrorString();
626 QgsMessageLog::logMessage( tr( "Atlas filename evaluation error: %1" ).arg( filenameExpression.evalErrorString() ), tr( "Layout" ) );
627 return false;
628 }
629
630 mCurrentFilename = filenameRes.toString();
631 }
632 return true;
633}
634
635bool QgsLayoutAtlas::prepareForFeature( const int featureI )
636{
637 if ( !mCoverageLayer )
638 {
639 return false;
640 }
641
642 if ( mFeatureIds.isEmpty() )
643 {
644 emit messagePushed( tr( "No matching atlas features" ) );
645 return false;
646 }
647
648 if ( featureI >= mFeatureIds.size() )
649 {
650 return false;
651 }
652
653 mCurrentFeatureNo = featureI;
654
655 // retrieve the next feature, based on its id
656 if ( !mCoverageLayer->getFeatures( QgsFeatureRequest().setFilterFid( mFeatureIds[ featureI ].first ) ).nextFeature( mCurrentFeature ) )
657 return false;
658
659 mLayout->reportContext().blockSignals( true ); // setFeature emits changed, we don't want 2 signals
660 mLayout->reportContext().setLayer( mCoverageLayer.get() );
661 mLayout->reportContext().blockSignals( false );
662 mLayout->reportContext().setFeature( mCurrentFeature );
663
664 // must come after we've set the report context feature, or the expression context will have an outdated atlas feature
665 const QgsExpressionContext expressionContext = createExpressionContext();
666
667 // generate filename for current feature
668 if ( !evalFeatureFilename( expressionContext ) )
669 {
670 //error evaluating filename
671 return false;
672 }
673
674 emit featureChanged( mCurrentFeature );
675 emit messagePushed( tr( "Atlas feature %1 of %2" ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
676
677 return mCurrentFeature.isValid();
678}
679
@ LimitCoverageLayerRenderToCurrentFeature
Limit coverage layer rendering to the current atlas feature.
Definition qgis.h:5322
@ HideCoverageLayer
Hide coverage layer in outputs.
Definition qgis.h:5315
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())
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:112
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:7451
#define Q_NOWARN_DEPRECATED_PUSH
Definition qgis.h:7450
_LayerRef< QgsVectorLayer > QgsVectorLayerRef