diff --git a/src/analysis/processing/qgsalgorithmlayoutatlastoimage.cpp b/src/analysis/processing/qgsalgorithmlayoutatlastoimage.cpp
index c58c7f7ada1a..bee9fb027432 100644
--- a/src/analysis/processing/qgsalgorithmlayoutatlastoimage.cpp
+++ b/src/analysis/processing/qgsalgorithmlayoutatlastoimage.cpp
@@ -75,7 +75,7 @@ void QgsLayoutAtlasToImageAlgorithm::initAlgorithm( const QVariantMap & )
addParameter( new QgsProcessingParameterExpression( QStringLiteral( "SORTBY_EXPRESSION" ), QObject::tr( "Sort expression" ), QString(), QStringLiteral( "COVERAGE_LAYER" ), true ) );
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "SORTBY_REVERSE" ), QObject::tr( "Reverse sort order (used when a sort expression is provided)" ), false ) );
- addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME_EXPRESSION" ), QObject::tr( "Output filename expression" ), QStringLiteral( "'output_'||@atlas_featurenumber" ), QStringLiteral( "COVERAGE_LAYER" ) ) );
+ addParameter( new QgsProcessingParameterExpression( QStringLiteral( "FILENAME_EXPRESSION" ), QObject::tr( "Output filename expression" ), QStringLiteral( "'output_'||@atlas_featurenumber_padded" ), QStringLiteral( "COVERAGE_LAYER" ) ) );
addParameter( new QgsProcessingParameterFile( QStringLiteral( "FOLDER" ), QObject::tr( "Output folder" ), Qgis::ProcessingFileParameterBehavior::Folder ) );
diff --git a/src/analysis/processing/qgsalgorithmlayoutatlastopdf.cpp b/src/analysis/processing/qgsalgorithmlayoutatlastopdf.cpp
index f678c6c2bec1..a70bc8e492ca 100644
--- a/src/analysis/processing/qgsalgorithmlayoutatlastopdf.cpp
+++ b/src/analysis/processing/qgsalgorithmlayoutatlastopdf.cpp
@@ -359,7 +359,7 @@ QVariantMap QgsLayoutAtlasToMultiplePdfAlgorithm::exportAtlas( QgsLayoutAtlas *a
QgsLayoutExporter::ExportResult result;
if ( atlas->filenameExpression().isEmpty() && filename.isEmpty() )
{
- atlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
+ atlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber_padded" ), error );
}
else if ( !filename.isEmpty() )
{
diff --git a/src/app/layout/qgslayoutdesignerdialog.cpp b/src/app/layout/qgslayoutdesignerdialog.cpp
index 3596563a9f13..1e6df52ea45b 100644
--- a/src/app/layout/qgslayoutdesignerdialog.cpp
+++ b/src/app/layout/qgslayoutdesignerdialog.cpp
@@ -2841,7 +2841,7 @@ void QgsLayoutDesignerDialog::exportAtlasToRaster()
return;
}
QString error;
- printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
+ printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber_padded" ), error );
}
else
{
@@ -3010,7 +3010,7 @@ void QgsLayoutDesignerDialog::exportAtlasToSvg()
return;
}
QString error;
- printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
+ printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber_padded" ), error );
}
QString lastUsedDir = defaultExportPath();
@@ -3202,7 +3202,7 @@ void QgsLayoutDesignerDialog::exportAtlasToPdf()
return;
}
QString error;
- printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber" ), error );
+ printAtlas->setFilenameExpression( QStringLiteral( "'output_'||@atlas_featurenumber_padded" ), error );
}
diff --git a/src/core/expression/qgsexpression.cpp b/src/core/expression/qgsexpression.cpp
index e9a5921a6618..7a48a743d85b 100644
--- a/src/core/expression/qgsexpression.cpp
+++ b/src/core/expression/qgsexpression.cpp
@@ -797,6 +797,7 @@ void QgsExpression::initVariableHelp()
sVariableHelpTexts()->insert( QStringLiteral( "atlas_layername" ), QCoreApplication::translate( "variable_help", "Current atlas coverage layer name." ) );
sVariableHelpTexts()->insert( QStringLiteral( "atlas_totalfeatures" ), QCoreApplication::translate( "variable_help", "Total number of features in atlas." ) );
sVariableHelpTexts()->insert( QStringLiteral( "atlas_featurenumber" ), QCoreApplication::translate( "variable_help", "Current atlas feature number." ) );
+ sVariableHelpTexts()->insert( QStringLiteral( "atlas_featurenumber_padded" ), QCoreApplication::translate( "variable_help", "Current atlas feature number (zero-padded)." ) );
sVariableHelpTexts()->insert( QStringLiteral( "atlas_filename" ), QCoreApplication::translate( "variable_help", "Current atlas file name." ) );
sVariableHelpTexts()->insert( QStringLiteral( "atlas_pagename" ), QCoreApplication::translate( "variable_help", "Current atlas page name." ) );
sVariableHelpTexts()->insert( QStringLiteral( "atlas_feature" ), QCoreApplication::translate( "variable_help", "Current atlas feature (as feature object)." ) );
diff --git a/src/core/expression/qgsexpressioncontextutils.cpp b/src/core/expression/qgsexpressioncontextutils.cpp
index 01304ea82731..3f3692456a6b 100644
--- a/src/core/expression/qgsexpressioncontextutils.cpp
+++ b/src/core/expression/qgsexpressioncontextutils.cpp
@@ -733,6 +733,8 @@ QgsExpressionContextScope *QgsExpressionContextUtils::atlasScope( const QgsLayou
//add known atlas variables
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_totalfeatures" ), atlas->count(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber" ), atlas->currentFeatureNumber() + 1, true, true ) );
+ const QString padded = QString::number( atlas->currentFeatureNumber() + 1 ).rightJustified( QString::number( atlas->count() ).size(), '0' );
+ scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_featurenumber_padded" ), padded, true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_filename" ), atlas->currentFilename(), true, true ) );
scope->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "atlas_pagename" ), atlas->nameForPage( atlas->currentFeatureNumber() ), true, true ) );
diff --git a/src/core/layout/qgslayoutatlas.cpp b/src/core/layout/qgslayoutatlas.cpp
index 775c101360d6..4d33a8faa958 100644
--- a/src/core/layout/qgslayoutatlas.cpp
+++ b/src/core/layout/qgslayoutatlas.cpp
@@ -33,7 +33,7 @@
QgsLayoutAtlas::QgsLayoutAtlas( QgsLayout *layout )
: QObject( layout )
, mLayout( layout )
- , mFilenameExpressionString( QStringLiteral( "'output_'||@atlas_featurenumber" ) )
+ , mFilenameExpressionString( QStringLiteral( "'output_'||@atlas_featurenumber_padded" ) )
{
//listen out for layer removal
diff --git a/src/gui/layout/qgslayoutatlaswidget.cpp b/src/gui/layout/qgslayoutatlaswidget.cpp
index 6b5ff64e2365..7cd79ec8502b 100644
--- a/src/gui/layout/qgslayoutatlaswidget.cpp
+++ b/src/gui/layout/qgslayoutatlaswidget.cpp
@@ -78,18 +78,15 @@ void QgsLayoutAtlasWidget::setMessageBar( QgsMessageBar *bar )
void QgsLayoutAtlasWidget::mUseAtlasCheckBox_stateChanged( int state )
{
- if ( state == Qt::Checked )
- {
- mAtlas->setEnabled( true );
- mConfigurationGroup->setEnabled( true );
- mOutputGroup->setEnabled( true );
- }
- else
- {
- mAtlas->setEnabled( false );
- mConfigurationGroup->setEnabled( false );
- mOutputGroup->setEnabled( false );
- }
+ const bool enabled = state == Qt::Checked;
+ mAtlas->setEnabled( enabled );
+ mAtlasCoverageLayerComboBox->setEnabled( enabled );
+ mAtlasCoverageLayerLabel->setEnabled( enabled );
+
+ const bool validLayer = mAtlas->coverageLayer() != nullptr;
+
+ mConfigurationGroup->setEnabled( enabled && validLayer );
+ mOutputGroup->setEnabled( enabled && validLayer );
}
void QgsLayoutAtlasWidget::changeCoverageLayer( QgsMapLayer *layer )
@@ -112,6 +109,9 @@ void QgsLayoutAtlasWidget::changeCoverageLayer( QgsMapLayer *layer )
updateAtlasFeatures();
}
+ mConfigurationGroup->setEnabled( mAtlas->enabled() && !vl );
+ mOutputGroup->setEnabled( mAtlas->enabled() && !vl );
+
// if page name expression is still valid, retain it. Otherwise switch to a nice default.
QgsExpression exp( prevPageNameExpression );
QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( vl ) );
@@ -192,18 +192,6 @@ void QgsLayoutAtlasWidget::mAtlasSingleFileCheckBox_stateChanged( int state )
{
if ( !mLayout )
return;
-
- if ( state == Qt::Checked )
- {
- mAtlasFilenamePatternEdit->setEnabled( false );
- mAtlasFilenameExpressionButton->setEnabled( false );
- }
- else
- {
- mAtlasFilenamePatternEdit->setEnabled( true );
- mAtlasFilenameExpressionButton->setEnabled( true );
- }
-
mLayout->setCustomProperty( QStringLiteral( "singleFile" ), state == Qt::Checked );
}
@@ -400,8 +388,6 @@ void QgsLayoutAtlasWidget::updateGuiElements()
const bool singleFile = mLayout->customProperty( QStringLiteral( "singleFile" ) ).toBool();
mAtlasSingleFileCheckBox->setCheckState( singleFile ? Qt::Checked : Qt::Unchecked );
- mAtlasFilenamePatternEdit->setEnabled( !singleFile );
- mAtlasFilenameExpressionButton->setEnabled( !singleFile );
mAtlasSortFeatureCheckBox->setCheckState( mAtlas->sortFeatures() ? Qt::Checked : Qt::Unchecked );
mAtlasSortFeatureDirectionButton->setEnabled( mAtlas->sortFeatures() );
diff --git a/src/ui/layout/qgslayoutatlaswidgetbase.ui b/src/ui/layout/qgslayoutatlaswidgetbase.ui
index 2ad279918ebf..a91907c51332 100644
--- a/src/ui/layout/qgslayoutatlaswidgetbase.ui
+++ b/src/ui/layout/qgslayoutatlaswidgetbase.ui
@@ -6,8 +6,8 @@
0
0
- 435
- 359
+ 430
+ 452
@@ -66,19 +66,6 @@
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
-
@@ -95,7 +82,7 @@
- -
+
-
Qt::WheelFocus
@@ -111,14 +98,35 @@
0
0
- 417
- 354
+ 426
+ 420
0
+
-
+
+
-
+
+
+ Coverage layer
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
-
@@ -181,13 +189,6 @@
- -
-
-
- Coverage layer
-
-
-
-
@@ -198,16 +199,6 @@
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
@@ -319,6 +310,19 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
@@ -353,7 +357,6 @@
mUseAtlasCheckBox
scrollArea
mConfigurationGroup
- mAtlasCoverageLayerComboBox
mAtlasHideCoverageCheckBox
mAtlasFeatureFilterCheckBox
mAtlasFeatureFilterEdit
diff --git a/tests/src/analysis/testqgsprocessingalgspt2.cpp b/tests/src/analysis/testqgsprocessingalgspt2.cpp
index 9ffd8e09732d..359d829c178e 100644
--- a/tests/src/analysis/testqgsprocessingalgspt2.cpp
+++ b/tests/src/analysis/testqgsprocessingalgspt2.cpp
@@ -413,9 +413,9 @@ void TestQgsProcessingAlgsPt2::exportAtlasLayoutPdfMultiple()
results = alg->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
- QVERIFY( QFile::exists( outputPdfDir + "/output_1.pdf" ) );
- QVERIFY( QFile::exists( outputPdfDir + "/output_2.pdf" ) );
- QVERIFY( QFile::exists( outputPdfDir + "/output_3.pdf" ) );
+ QVERIFY( QFile::exists( outputPdfDir + "/output_01.pdf" ) );
+ QVERIFY( QFile::exists( outputPdfDir + "/output_02.pdf" ) );
+ QVERIFY( QFile::exists( outputPdfDir + "/output_03.pdf" ) );
}
void TestQgsProcessingAlgsPt2::exportAtlasLayoutPng()