19 #include <QtAlgorithms>
32 , mFilenameExpressionString( QStringLiteral(
"'output_'||@atlas_featurenumber" ) )
41 return QStringLiteral(
"atlas" );
51 return mLayout.data();
56 QDomElement atlasElem = document.createElement( QStringLiteral(
"Atlas" ) );
57 atlasElem.setAttribute( QStringLiteral(
"enabled" ), mEnabled ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
61 atlasElem.setAttribute( QStringLiteral(
"coverageLayer" ), mCoverageLayer.
layerId );
62 atlasElem.setAttribute( QStringLiteral(
"coverageLayerName" ), mCoverageLayer.
name );
63 atlasElem.setAttribute( QStringLiteral(
"coverageLayerSource" ), mCoverageLayer.
source );
64 atlasElem.setAttribute( QStringLiteral(
"coverageLayerProvider" ), mCoverageLayer.
provider );
68 atlasElem.setAttribute( QStringLiteral(
"coverageLayer" ), QString() );
71 atlasElem.setAttribute( QStringLiteral(
"hideCoverage" ), mHideCoverage ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
72 atlasElem.setAttribute( QStringLiteral(
"filenamePattern" ), mFilenameExpressionString );
73 atlasElem.setAttribute( QStringLiteral(
"pageNameExpression" ), mPageNameExpression );
75 atlasElem.setAttribute( QStringLiteral(
"sortFeatures" ), mSortFeatures ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
78 atlasElem.setAttribute( QStringLiteral(
"sortKey" ), mSortExpression );
79 atlasElem.setAttribute( QStringLiteral(
"sortAscending" ), mSortAscending ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
81 atlasElem.setAttribute( QStringLiteral(
"filterFeatures" ), mFilterFeatures ? QStringLiteral(
"1" ) : QStringLiteral(
"0" ) );
82 if ( mFilterFeatures )
84 atlasElem.setAttribute( QStringLiteral(
"featureFilter" ), mFilterExpression );
87 parentElement.appendChild( atlasElem );
94 mEnabled = atlasElem.attribute( QStringLiteral(
"enabled" ), QStringLiteral(
"0" ) ).toInt();
97 QString layerId = atlasElem.attribute( QStringLiteral(
"coverageLayer" ) );
98 QString layerName = atlasElem.attribute( QStringLiteral(
"coverageLayerName" ) );
99 QString layerSource = atlasElem.attribute( QStringLiteral(
"coverageLayerSource" ) );
100 QString layerProvider = atlasElem.attribute( QStringLiteral(
"coverageLayerProvider" ) );
102 mCoverageLayer =
QgsVectorLayerRef( layerId, layerName, layerSource, layerProvider );
104 mLayout->reportContext().setLayer( mCoverageLayer.
get() );
106 mPageNameExpression = atlasElem.attribute( QStringLiteral(
"pageNameExpression" ), QString() );
108 setFilenameExpression( atlasElem.attribute( QStringLiteral(
"filenamePattern" ), QString() ), error );
110 mSortFeatures = atlasElem.attribute( QStringLiteral(
"sortFeatures" ), QStringLiteral(
"0" ) ).toInt();
111 mSortExpression = atlasElem.attribute( QStringLiteral(
"sortKey" ) );
112 mSortAscending = atlasElem.attribute( QStringLiteral(
"sortAscending" ), QStringLiteral(
"1" ) ).toInt();
113 mFilterFeatures = atlasElem.attribute( QStringLiteral(
"filterFeatures" ), QStringLiteral(
"0" ) ).toInt();
114 mFilterExpression = atlasElem.attribute( QStringLiteral(
"featureFilter" ) );
116 mHideCoverage = atlasElem.attribute( QStringLiteral(
"hideCoverage" ), QStringLiteral(
"0" ) ).toInt();
135 void QgsLayoutAtlas::removeLayers(
const QStringList &layers )
137 if ( !mCoverageLayer )
142 for (
const QString &layerId : layers )
144 if ( layerId == mCoverageLayer.
layerId )
156 if ( layer == mCoverageLayer.
get() )
167 if ( mPageNameExpression == expression )
170 mPageNameExpression = expression;
176 if ( pageNumber < 0 || pageNumber >= mFeatureIds.count() )
179 return mFeatureIds.at( pageNumber ).second;
184 if ( mSortFeatures ==
enabled )
193 if ( mSortAscending == ascending )
196 mSortAscending = ascending;
202 if ( mSortExpression == expression )
205 mSortExpression = expression;
211 if ( mFilterFeatures == filtered )
214 mFilterFeatures = filtered;
221 const bool hasChanged = mFilterExpression != expression;
222 mFilterExpression = expression;
238 class AtlasFeatureSorter
241 AtlasFeatureSorter( QgsLayoutAtlas::SorterKeys &keys,
bool ascending =
true )
243 , mAscending( ascending )
246 bool operator()(
const QPair< QgsFeatureId, QString > &id1,
const QPair< QgsFeatureId, QString > &id2 )
248 return mAscending ?
qgsVariantLessThan( mKeys.value( id1.first ), mKeys.value( id2.first ) )
253 QgsLayoutAtlas::SorterKeys &mKeys;
261 mCurrentFeatureNo = -1;
262 if ( !mCoverageLayer )
270 updateFilenameExpression( error );
277 mFilterParserError.clear();
278 if ( mFilterFeatures && !mFilterExpression.isEmpty() )
293 std::unique_ptr<QgsExpression> nameExpression;
294 if ( !mPageNameExpression.isEmpty() )
296 nameExpression = qgis::make_unique< QgsExpression >( mPageNameExpression );
297 if ( nameExpression->hasParserError() )
299 nameExpression.reset(
nullptr );
303 nameExpression->prepare( &expressionContext );
311 mFeatureKeys.clear();
314 if ( mSortFeatures && !mSortExpression.isEmpty() )
316 sortExpression = qgis::make_unique< QgsExpression >( mSortExpression );
332 if ( nameExpression )
334 QVariant result = nameExpression->evaluate( &expressionContext );
335 if ( nameExpression->hasEvalError() )
339 pageName = result.toString();
342 mFeatureIds.push_back( qMakePair( feat.
id(), pageName ) );
351 mFeatureKeys.insert( feat.
id(), result );
356 if ( !mFeatureKeys.isEmpty() )
359 std::sort( mFeatureIds.begin(), mFeatureIds.end(), sorter );
363 return mFeatureIds.size();
368 if ( !mCoverageLayer )
393 return mFeatureIds.size();
398 QFileInfo fi( baseFilePath );
400 QString base = dir.filePath( mCurrentFilename );
401 if ( !extension.startsWith(
'.' ) )
409 int newFeatureNo = mCurrentFeatureNo + 1;
410 if ( newFeatureNo >= mFeatureIds.size() )
415 return prepareForFeature( newFeatureNo );
420 int newFeatureNo = mCurrentFeatureNo - 1;
421 if ( newFeatureNo < 0 )
426 return prepareForFeature( newFeatureNo );
431 return prepareForFeature( 0 );
436 return prepareForFeature( mFeatureIds.size() - 1 );
441 return prepareForFeature( feature );
447 auto it = mFeatureIds.constBegin();
448 for (
int currentIdx = 0; it != mFeatureIds.constEnd(); ++it, ++currentIdx )
450 if ( ( *it ).first == feature.
id() )
468 prepareForFeature( mCurrentFeatureNo );
474 if ( hide == mHideCoverage )
477 mHideCoverage = hide;
484 const bool hasChanged = mFilenameExpressionString != pattern;
485 mFilenameExpressionString = pattern;
490 return updateFilenameExpression( errorString );
495 return mCurrentFilename;
508 if ( mCoverageLayer )
511 if ( mLayout && mEnabled )
513 if ( mCurrentFeature.
isValid() )
517 else if ( mCoverageLayer )
520 feature.setValid(
true );
524 return expressionContext;
527 bool QgsLayoutAtlas::updateFilenameExpression( QString &error )
529 if ( !mCoverageLayer )
535 bool evalResult {
true };
537 if ( !mFilenameExpressionString.isEmpty() )
539 mFilenameExpression =
QgsExpression( mFilenameExpressionString );
549 evalResult = mFilenameExpression.
prepare( &expressionContext );
555 evalResult = evalFeatureFilename( expressionContext );
569 if ( !mFilenameExpressionString.isEmpty() && mFilenameExpression.
isValid() )
571 QVariant filenameRes = mFilenameExpression.
evaluate( &context );
578 mCurrentFilename = filenameRes.toString();
583 bool QgsLayoutAtlas::prepareForFeature(
const int featureI )
585 if ( !mCoverageLayer )
590 if ( mFeatureIds.isEmpty() )
596 if ( featureI >= mFeatureIds.size() )
601 mCurrentFeatureNo = featureI;
607 mLayout->reportContext().blockSignals(
true );
608 mLayout->reportContext().setLayer( mCoverageLayer.
get() );
609 mLayout->reportContext().blockSignals(
false );
610 mLayout->reportContext().setFeature( mCurrentFeature );
616 if ( !evalFeatureFilename( expressionContext ) )
623 emit
messagePushed( tr(
"Atlas feature %1 of %2" ).arg( featureI + 1 ).arg( mFeatureIds.size() ) );
625 return mCurrentFeature.
isValid();