28#include <QImageWriter>
31#include "moc_qgslayoutatlaswidget.cpp"
33using namespace Qt::StringLiterals;
38 , mAtlas( layout->atlas() )
41 connect( mUseAtlasCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mUseAtlasCheckBox_stateChanged );
42 connect( mAtlasFilenamePatternEdit, &QLineEdit::editingFinished,
this, &QgsLayoutAtlasWidget::mAtlasFilenamePatternEdit_editingFinished );
43 connect( mAtlasFilenameExpressionButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasFilenameExpressionButton_clicked );
44 connect( mAtlasLimitCoverageLayerRenderCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasLimitCoverageLayerRenderCheckBox_stateChanged );
45 connect( mAtlasHideCoverageCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasHideCoverageCheckBox_stateChanged );
46 connect( mAtlasSingleFileCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasSingleFileCheckBox_stateChanged );
47 connect( mAtlasSortFeatureCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasSortFeatureCheckBox_stateChanged );
48 connect( mAtlasSortFeatureDirectionButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasSortFeatureDirectionButton_clicked );
49 connect( mAtlasFeatureFilterEdit, &QLineEdit::editingFinished,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterEdit_editingFinished );
50 connect( mAtlasFeatureFilterButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterButton_clicked );
51 connect( mAtlasFeatureFilterCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterCheckBox_stateChanged );
62 mAtlasSortFeatureDirectionButton->setEnabled(
false );
63 mAtlasSortExpressionWidget->setEnabled(
false );
68 mPageNameWidget->registerExpressionContextGenerator( mLayout );
70 const QList<QByteArray> formats = QImageWriter::supportedImageFormats();
71 for (
int i = 0; i < formats.size(); ++i )
73 mAtlasFileFormat->addItem( QString( formats.at( i ) ) );
75 connect( mAtlasFileFormat, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [
this](
int ) { changeFileFormat(); } );
85void QgsLayoutAtlasWidget::mUseAtlasCheckBox_stateChanged(
int state )
87 if ( state == Qt::Checked )
90 mConfigurationGroup->setEnabled(
true );
91 mOutputGroup->setEnabled(
true );
95 mAtlas->setEnabled(
false );
96 mConfigurationGroup->setEnabled(
false );
97 mOutputGroup->setEnabled(
false );
101void QgsLayoutAtlasWidget::changeCoverageLayer(
QgsMapLayer *layer )
106 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
108 const QString prevPageNameExpression = mAtlas->pageNameExpression();
109 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Layer" ) );
110 mLayout->reportContext().setLayer( vl );
113 mAtlas->setCoverageLayer(
nullptr );
117 mAtlas->setCoverageLayer( vl );
118 updateAtlasFeatures();
122 QgsExpression exp( prevPageNameExpression );
124 if ( exp.prepare( &context ) && !exp.hasParserError() )
126 mAtlas->setPageNameExpression( prevPageNameExpression );
133 mLayout->undoStack()->endCommand();
136void QgsLayoutAtlasWidget::mAtlasFilenamePatternEdit_editingFinished()
142 mBlockUpdates =
true;
143 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filename" ) );
144 if ( !mAtlas->setFilenameExpression( mAtlasFilenamePatternEdit->text(), error ) )
147 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filename expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFilenamePatternEdit->text(), error ) );
149 mLayout->undoStack()->endCommand();
150 mBlockUpdates =
false;
153void QgsLayoutAtlasWidget::mAtlasFilenameExpressionButton_clicked()
155 if ( !mLayout || !mAtlas || !mAtlas->coverageLayer() )
160 const QgsExpressionContext context = mLayout->createExpressionContext();
161 QgsExpressionBuilderDialog exprDlg( mAtlas->coverageLayer(), mAtlasFilenamePatternEdit->text(),
this, u
"generic"_s, context );
162 exprDlg.setWindowTitle( tr(
"Expression Based Filename" ) );
164 if ( exprDlg.exec() == QDialog::Accepted )
166 const QString expression = exprDlg.expressionText();
167 if ( !expression.isEmpty() )
170 mAtlasFilenamePatternEdit->setText( expression );
172 mBlockUpdates =
true;
173 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filename" ) );
174 if ( !mAtlas->setFilenameExpression( expression, error ) )
177 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filename expression to '%1'.\nParser error:\n%2" ).arg( expression, error ) );
179 mBlockUpdates =
false;
180 mLayout->undoStack()->endCommand();
185void QgsLayoutAtlasWidget::mAtlasLimitCoverageLayerRenderCheckBox_stateChanged(
int state )
190 mBlockUpdates =
true;
191 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Limit Atlas Layer Rendering to Current Feature" ) );
192 mAtlas->setLimitCoverageLayerRenderToCurrentFeature( state == Qt::Checked );
193 mLayout->undoStack()->endCommand();
194 mBlockUpdates =
false;
197void QgsLayoutAtlasWidget::mAtlasHideCoverageCheckBox_stateChanged(
int state )
202 mBlockUpdates =
true;
203 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Atlas Layer Visibility" ) );
204 mAtlas->setHideCoverage( state == Qt::Checked );
205 mLayout->undoStack()->endCommand();
206 mBlockUpdates =
false;
208 mAtlasLimitCoverageLayerRenderCheckBox->setEnabled( state != Qt::Checked );
211void QgsLayoutAtlasWidget::mAtlasSingleFileCheckBox_stateChanged(
int state )
216 if ( state == Qt::Checked )
218 mAtlasFilenamePatternEdit->setEnabled(
false );
219 mAtlasFilenameExpressionButton->setEnabled(
false );
223 mAtlasFilenamePatternEdit->setEnabled(
true );
224 mAtlasFilenameExpressionButton->setEnabled(
true );
227 mLayout->setCustomProperty( u
"singleFile"_s, state == Qt::Checked );
230void QgsLayoutAtlasWidget::mAtlasSortFeatureCheckBox_stateChanged(
int state )
235 if ( state == Qt::Checked )
237 mAtlasSortFeatureDirectionButton->setEnabled(
true );
238 mAtlasSortExpressionWidget->setEnabled(
true );
242 mAtlasSortFeatureDirectionButton->setEnabled(
false );
243 mAtlasSortExpressionWidget->setEnabled(
false );
245 mBlockUpdates =
true;
246 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Atlas Sorting" ) );
247 mAtlas->setSortFeatures( state == Qt::Checked );
248 mLayout->undoStack()->endCommand();
249 mBlockUpdates =
false;
250 updateAtlasFeatures();
253void QgsLayoutAtlasWidget::changesSortFeatureExpression(
const QString &expression,
bool )
258 mBlockUpdates =
true;
259 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Sort" ) );
260 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mAtlasCoverageLayerComboBox->currentLayer() );
262 mLayout->undoStack()->endCommand();
263 mBlockUpdates =
false;
264 updateAtlasFeatures();
267void QgsLayoutAtlasWidget::updateAtlasFeatures()
269 const bool updated = mAtlas->updateFeatures();
272 mMessageBar->pushInfo( tr(
"Atlas" ), tr(
"No matching atlas features found!" ) );
279void QgsLayoutAtlasWidget::mAtlasFeatureFilterCheckBox_stateChanged(
int state )
284 if ( state == Qt::Checked )
286 mAtlasFeatureFilterEdit->setEnabled(
true );
287 mAtlasFeatureFilterButton->setEnabled(
true );
291 mAtlasFeatureFilterEdit->setEnabled(
false );
292 mAtlasFeatureFilterButton->setEnabled(
false );
294 mBlockUpdates =
true;
295 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
296 mAtlas->setFilterFeatures( state == Qt::Checked );
297 mLayout->undoStack()->endCommand();
298 mBlockUpdates =
false;
299 updateAtlasFeatures();
302void QgsLayoutAtlasWidget::pageNameExpressionChanged(
const QString &,
bool valid )
307 const QString expression = mPageNameWidget->asExpression();
308 if ( !valid && !expression.isEmpty() )
313 mBlockUpdates =
true;
314 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Name" ) );
315 mAtlas->setPageNameExpression( expression );
316 mLayout->undoStack()->endCommand();
317 mBlockUpdates =
false;
320void QgsLayoutAtlasWidget::mAtlasFeatureFilterEdit_editingFinished()
326 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
328 mBlockUpdates =
true;
329 if ( !mAtlas->setFilterExpression( mAtlasFeatureFilterEdit->text(), error ) )
332 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filter expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFeatureFilterEdit->text(), error ) );
334 mBlockUpdates =
false;
335 mLayout->undoStack()->endCommand();
336 updateAtlasFeatures();
339void QgsLayoutAtlasWidget::mAtlasFeatureFilterButton_clicked()
344 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mAtlasCoverageLayerComboBox->currentLayer() );
351 const QgsExpressionContext context = mLayout->createExpressionContext();
352 QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(),
this, u
"generic"_s, context );
353 exprDlg.setWindowTitle( tr(
"Expression Based Filter" ) );
355 if ( exprDlg.exec() == QDialog::Accepted )
357 const QString expression = exprDlg.expressionText();
358 if ( !expression.isEmpty() )
360 mAtlasFeatureFilterEdit->setText( expression );
362 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
363 mBlockUpdates =
true;
364 if ( !mAtlas->setFilterExpression( mAtlasFeatureFilterEdit->text(), error ) )
367 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filter expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFeatureFilterEdit->text(), error ) );
369 mBlockUpdates =
false;
370 mLayout->undoStack()->endCommand();
371 updateAtlasFeatures();
376void QgsLayoutAtlasWidget::mAtlasSortFeatureDirectionButton_clicked()
381 Qt::ArrowType at = mAtlasSortFeatureDirectionButton->arrowType();
382 at = ( at == Qt::UpArrow ) ? Qt::DownArrow : Qt::UpArrow;
383 mAtlasSortFeatureDirectionButton->setArrowType( at );
385 mBlockUpdates =
true;
386 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Sort" ) );
387 mAtlas->setSortAscending( at == Qt::UpArrow );
388 mLayout->undoStack()->endCommand();
389 mBlockUpdates =
false;
390 updateAtlasFeatures();
393void QgsLayoutAtlasWidget::changeFileFormat()
398 mLayout->setCustomProperty( u
"atlasRasterFormat"_s, mAtlasFileFormat->currentText() );
401void QgsLayoutAtlasWidget::updateGuiElements()
406 blockAllSignals(
true );
407 mUseAtlasCheckBox->setCheckState( mAtlas->enabled() ? Qt::Checked : Qt::Unchecked );
408 mConfigurationGroup->setEnabled( mAtlas->enabled() );
409 mOutputGroup->setEnabled( mAtlas->enabled() );
411 mAtlasCoverageLayerComboBox->setLayer( mAtlas->coverageLayer() );
412 mPageNameWidget->setLayer( mAtlas->coverageLayer() );
413 mPageNameWidget->setField( mAtlas->pageNameExpression() );
415 mAtlasSortExpressionWidget->setLayer( mAtlas->coverageLayer() );
416 mAtlasSortExpressionWidget->setField( mAtlas->sortExpression() );
418 mAtlasFilenamePatternEdit->setText( mAtlas->filenameExpression() );
419 mAtlasLimitCoverageLayerRenderCheckBox->setCheckState( mAtlas->limitCoverageLayerRenderToCurrentFeature() ? Qt::Checked : Qt::Unchecked );
420 mAtlasHideCoverageCheckBox->setCheckState( mAtlas->hideCoverage() ? Qt::Checked : Qt::Unchecked );
422 const bool singleFile = mLayout->customProperty( u
"singleFile"_s,
true ).toBool();
423 mAtlasSingleFileCheckBox->setCheckState( singleFile ? Qt::Checked : Qt::Unchecked );
424 mAtlasFilenamePatternEdit->setEnabled( !singleFile );
425 mAtlasFilenameExpressionButton->setEnabled( !singleFile );
427 mAtlasSortFeatureCheckBox->setCheckState( mAtlas->sortFeatures() ? Qt::Checked : Qt::Unchecked );
428 mAtlasSortFeatureDirectionButton->setEnabled( mAtlas->sortFeatures() );
429 mAtlasSortExpressionWidget->setEnabled( mAtlas->sortFeatures() );
431 mAtlasSortFeatureDirectionButton->setArrowType( mAtlas->sortAscending() ? Qt::UpArrow : Qt::DownArrow );
432 mAtlasFeatureFilterEdit->setText( mAtlas->filterExpression() );
434 mAtlasFeatureFilterCheckBox->setCheckState( mAtlas->filterFeatures() ? Qt::Checked : Qt::Unchecked );
435 mAtlasFeatureFilterEdit->setEnabled( mAtlas->filterFeatures() );
436 mAtlasFeatureFilterButton->setEnabled( mAtlas->filterFeatures() );
438 mAtlasFileFormat->setCurrentIndex( mAtlasFileFormat->findText( mLayout->customProperty( u
"atlasRasterFormat"_s, u
"png"_s ).toString() ) );
440 blockAllSignals(
false );
443void QgsLayoutAtlasWidget::blockAllSignals(
bool b )
445 mUseAtlasCheckBox->blockSignals( b );
446 mConfigurationGroup->blockSignals( b );
447 mOutputGroup->blockSignals( b );
448 mAtlasCoverageLayerComboBox->blockSignals( b );
449 mPageNameWidget->blockSignals( b );
450 mAtlasSortExpressionWidget->blockSignals( b );
451 mAtlasFilenamePatternEdit->blockSignals( b );
452 mAtlasLimitCoverageLayerRenderCheckBox->blockSignals( b );
453 mAtlasHideCoverageCheckBox->blockSignals( b );
454 mAtlasSingleFileCheckBox->blockSignals( b );
455 mAtlasSortFeatureCheckBox->blockSignals( b );
456 mAtlasSortFeatureDirectionButton->blockSignals( b );
457 mAtlasFeatureFilterEdit->blockSignals( b );
458 mAtlasFeatureFilterCheckBox->blockSignals( b );
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
static QString quoteFieldExpression(const QString &expression, const QgsVectorLayer *layer)
Validate if the expression is a field in the layer and ensure it is quoted.
void setEnabled(bool enabled)
Sets whether the atlas is enabled.
void changed()
Emitted when one of the atlas parameters changes.
void layerChanged(QgsMapLayer *layer)
Emitted whenever the currently selected layer changes.
Base class for all map layer types.
A bar for displaying non-blocking messages to the user.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
QString displayExpression