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