28#include <QImageWriter>
30#include "moc_qgslayoutatlaswidget.cpp"
35 , mAtlas( layout->atlas() )
38 connect( mUseAtlasCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mUseAtlasCheckBox_stateChanged );
39 connect( mAtlasFilenamePatternEdit, &QLineEdit::editingFinished,
this, &QgsLayoutAtlasWidget::mAtlasFilenamePatternEdit_editingFinished );
40 connect( mAtlasFilenameExpressionButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasFilenameExpressionButton_clicked );
41 connect( mAtlasLimitCoverageLayerRenderCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasLimitCoverageLayerRenderCheckBox_stateChanged );
42 connect( mAtlasHideCoverageCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasHideCoverageCheckBox_stateChanged );
43 connect( mAtlasSingleFileCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasSingleFileCheckBox_stateChanged );
44 connect( mAtlasSortFeatureCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasSortFeatureCheckBox_stateChanged );
45 connect( mAtlasSortFeatureDirectionButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasSortFeatureDirectionButton_clicked );
46 connect( mAtlasFeatureFilterEdit, &QLineEdit::editingFinished,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterEdit_editingFinished );
47 connect( mAtlasFeatureFilterButton, &QToolButton::clicked,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterButton_clicked );
48 connect( mAtlasFeatureFilterCheckBox, &QCheckBox::stateChanged,
this, &QgsLayoutAtlasWidget::mAtlasFeatureFilterCheckBox_stateChanged );
59 mAtlasSortFeatureDirectionButton->setEnabled(
false );
60 mAtlasSortExpressionWidget->setEnabled(
false );
65 mPageNameWidget->registerExpressionContextGenerator( mLayout );
67 const QList<QByteArray> formats = QImageWriter::supportedImageFormats();
68 for (
int i = 0; i < formats.size(); ++i )
70 mAtlasFileFormat->addItem( QString( formats.at( i ) ) );
72 connect( mAtlasFileFormat, qOverload<int>( &QComboBox::currentIndexChanged ),
this, [
this](
int ) { changeFileFormat(); } );
82void QgsLayoutAtlasWidget::mUseAtlasCheckBox_stateChanged(
int state )
84 if ( state == Qt::Checked )
87 mConfigurationGroup->setEnabled(
true );
88 mOutputGroup->setEnabled(
true );
92 mAtlas->setEnabled(
false );
93 mConfigurationGroup->setEnabled(
false );
94 mOutputGroup->setEnabled(
false );
98void QgsLayoutAtlasWidget::changeCoverageLayer(
QgsMapLayer *layer )
103 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
105 const QString prevPageNameExpression = mAtlas->pageNameExpression();
106 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Layer" ) );
107 mLayout->reportContext().setLayer( vl );
110 mAtlas->setCoverageLayer(
nullptr );
114 mAtlas->setCoverageLayer( vl );
115 updateAtlasFeatures();
119 QgsExpression exp( prevPageNameExpression );
121 if ( exp.prepare( &context ) && !exp.hasParserError() )
123 mAtlas->setPageNameExpression( prevPageNameExpression );
130 mLayout->undoStack()->endCommand();
133void QgsLayoutAtlasWidget::mAtlasFilenamePatternEdit_editingFinished()
139 mBlockUpdates =
true;
140 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filename" ) );
141 if ( !mAtlas->setFilenameExpression( mAtlasFilenamePatternEdit->text(), error ) )
144 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filename expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFilenamePatternEdit->text(), error ) );
146 mLayout->undoStack()->endCommand();
147 mBlockUpdates =
false;
150void QgsLayoutAtlasWidget::mAtlasFilenameExpressionButton_clicked()
152 if ( !mLayout || !mAtlas || !mAtlas->coverageLayer() )
157 const QgsExpressionContext context = mLayout->createExpressionContext();
158 QgsExpressionBuilderDialog exprDlg( mAtlas->coverageLayer(), mAtlasFilenamePatternEdit->text(),
this, QStringLiteral(
"generic" ), context );
159 exprDlg.setWindowTitle( tr(
"Expression Based Filename" ) );
161 if ( exprDlg.exec() == QDialog::Accepted )
163 const QString expression = exprDlg.expressionText();
164 if ( !expression.isEmpty() )
167 mAtlasFilenamePatternEdit->setText( expression );
169 mBlockUpdates =
true;
170 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filename" ) );
171 if ( !mAtlas->setFilenameExpression( expression, error ) )
174 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filename expression to '%1'.\nParser error:\n%2" ).arg( expression, error ) );
176 mBlockUpdates =
false;
177 mLayout->undoStack()->endCommand();
182void QgsLayoutAtlasWidget::mAtlasLimitCoverageLayerRenderCheckBox_stateChanged(
int state )
187 mBlockUpdates =
true;
188 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Limit Atlas Layer Rendering to Current Feature" ) );
189 mAtlas->setLimitCoverageLayerRenderToCurrentFeature( state == Qt::Checked );
190 mLayout->undoStack()->endCommand();
191 mBlockUpdates =
false;
194void QgsLayoutAtlasWidget::mAtlasHideCoverageCheckBox_stateChanged(
int state )
199 mBlockUpdates =
true;
200 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Atlas Layer Visibility" ) );
201 mAtlas->setHideCoverage( state == Qt::Checked );
202 mLayout->undoStack()->endCommand();
203 mBlockUpdates =
false;
205 mAtlasLimitCoverageLayerRenderCheckBox->setEnabled( state != Qt::Checked );
208void QgsLayoutAtlasWidget::mAtlasSingleFileCheckBox_stateChanged(
int state )
213 if ( state == Qt::Checked )
215 mAtlasFilenamePatternEdit->setEnabled(
false );
216 mAtlasFilenameExpressionButton->setEnabled(
false );
220 mAtlasFilenamePatternEdit->setEnabled(
true );
221 mAtlasFilenameExpressionButton->setEnabled(
true );
224 mLayout->setCustomProperty( QStringLiteral(
"singleFile" ), state == Qt::Checked );
227void QgsLayoutAtlasWidget::mAtlasSortFeatureCheckBox_stateChanged(
int state )
232 if ( state == Qt::Checked )
234 mAtlasSortFeatureDirectionButton->setEnabled(
true );
235 mAtlasSortExpressionWidget->setEnabled(
true );
239 mAtlasSortFeatureDirectionButton->setEnabled(
false );
240 mAtlasSortExpressionWidget->setEnabled(
false );
242 mBlockUpdates =
true;
243 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Toggle Atlas Sorting" ) );
244 mAtlas->setSortFeatures( state == Qt::Checked );
245 mLayout->undoStack()->endCommand();
246 mBlockUpdates =
false;
247 updateAtlasFeatures();
250void QgsLayoutAtlasWidget::changesSortFeatureExpression(
const QString &expression,
bool )
255 mBlockUpdates =
true;
256 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Sort" ) );
257 QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mAtlasCoverageLayerComboBox->currentLayer() );
259 mLayout->undoStack()->endCommand();
260 mBlockUpdates =
false;
261 updateAtlasFeatures();
264void QgsLayoutAtlasWidget::updateAtlasFeatures()
266 const bool updated = mAtlas->updateFeatures();
269 mMessageBar->pushInfo( tr(
"Atlas" ), tr(
"No matching atlas features found!" ) );
276void QgsLayoutAtlasWidget::mAtlasFeatureFilterCheckBox_stateChanged(
int state )
281 if ( state == Qt::Checked )
283 mAtlasFeatureFilterEdit->setEnabled(
true );
284 mAtlasFeatureFilterButton->setEnabled(
true );
288 mAtlasFeatureFilterEdit->setEnabled(
false );
289 mAtlasFeatureFilterButton->setEnabled(
false );
291 mBlockUpdates =
true;
292 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
293 mAtlas->setFilterFeatures( state == Qt::Checked );
294 mLayout->undoStack()->endCommand();
295 mBlockUpdates =
false;
296 updateAtlasFeatures();
299void QgsLayoutAtlasWidget::pageNameExpressionChanged(
const QString &,
bool valid )
304 const QString expression = mPageNameWidget->asExpression();
305 if ( !valid && !expression.isEmpty() )
310 mBlockUpdates =
true;
311 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Name" ) );
312 mAtlas->setPageNameExpression( expression );
313 mLayout->undoStack()->endCommand();
314 mBlockUpdates =
false;
317void QgsLayoutAtlasWidget::mAtlasFeatureFilterEdit_editingFinished()
323 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
325 mBlockUpdates =
true;
326 if ( !mAtlas->setFilterExpression( mAtlasFeatureFilterEdit->text(), error ) )
329 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filter expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFeatureFilterEdit->text(), error ) );
331 mBlockUpdates =
false;
332 mLayout->undoStack()->endCommand();
333 updateAtlasFeatures();
336void QgsLayoutAtlasWidget::mAtlasFeatureFilterButton_clicked()
341 QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( mAtlasCoverageLayerComboBox->currentLayer() );
348 const QgsExpressionContext context = mLayout->createExpressionContext();
349 QgsExpressionBuilderDialog exprDlg( vl, mAtlasFeatureFilterEdit->text(),
this, QStringLiteral(
"generic" ), context );
350 exprDlg.setWindowTitle( tr(
"Expression Based Filter" ) );
352 if ( exprDlg.exec() == QDialog::Accepted )
354 const QString expression = exprDlg.expressionText();
355 if ( !expression.isEmpty() )
357 mAtlasFeatureFilterEdit->setText( expression );
359 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Filter" ) );
360 mBlockUpdates =
true;
361 if ( !mAtlas->setFilterExpression( mAtlasFeatureFilterEdit->text(), error ) )
364 mMessageBar->pushWarning( tr(
"Atlas" ), tr(
"Could not set filter expression to '%1'.\nParser error:\n%2" ).arg( mAtlasFeatureFilterEdit->text(), error ) );
366 mBlockUpdates =
false;
367 mLayout->undoStack()->endCommand();
368 updateAtlasFeatures();
373void QgsLayoutAtlasWidget::mAtlasSortFeatureDirectionButton_clicked()
378 Qt::ArrowType at = mAtlasSortFeatureDirectionButton->arrowType();
379 at = ( at == Qt::UpArrow ) ? Qt::DownArrow : Qt::UpArrow;
380 mAtlasSortFeatureDirectionButton->setArrowType( at );
382 mBlockUpdates =
true;
383 mLayout->undoStack()->beginCommand( mAtlas, tr(
"Change Atlas Sort" ) );
384 mAtlas->setSortAscending( at == Qt::UpArrow );
385 mLayout->undoStack()->endCommand();
386 mBlockUpdates =
false;
387 updateAtlasFeatures();
390void QgsLayoutAtlasWidget::changeFileFormat()
395 mLayout->setCustomProperty( QStringLiteral(
"atlasRasterFormat" ), mAtlasFileFormat->currentText() );
398void QgsLayoutAtlasWidget::updateGuiElements()
403 blockAllSignals(
true );
404 mUseAtlasCheckBox->setCheckState( mAtlas->enabled() ? Qt::Checked : Qt::Unchecked );
405 mConfigurationGroup->setEnabled( mAtlas->enabled() );
406 mOutputGroup->setEnabled( mAtlas->enabled() );
408 mAtlasCoverageLayerComboBox->setLayer( mAtlas->coverageLayer() );
409 mPageNameWidget->setLayer( mAtlas->coverageLayer() );
410 mPageNameWidget->setField( mAtlas->pageNameExpression() );
412 mAtlasSortExpressionWidget->setLayer( mAtlas->coverageLayer() );
413 mAtlasSortExpressionWidget->setField( mAtlas->sortExpression() );
415 mAtlasFilenamePatternEdit->setText( mAtlas->filenameExpression() );
416 mAtlasLimitCoverageLayerRenderCheckBox->setCheckState( mAtlas->limitCoverageLayerRenderToCurrentFeature() ? Qt::Checked : Qt::Unchecked );
417 mAtlasHideCoverageCheckBox->setCheckState( mAtlas->hideCoverage() ? Qt::Checked : Qt::Unchecked );
419 const bool singleFile = mLayout->customProperty( QStringLiteral(
"singleFile" ) ).toBool();
420 mAtlasSingleFileCheckBox->setCheckState( singleFile ? Qt::Checked : Qt::Unchecked );
421 mAtlasFilenamePatternEdit->setEnabled( !singleFile );
422 mAtlasFilenameExpressionButton->setEnabled( !singleFile );
424 mAtlasSortFeatureCheckBox->setCheckState( mAtlas->sortFeatures() ? Qt::Checked : Qt::Unchecked );
425 mAtlasSortFeatureDirectionButton->setEnabled( mAtlas->sortFeatures() );
426 mAtlasSortExpressionWidget->setEnabled( mAtlas->sortFeatures() );
428 mAtlasSortFeatureDirectionButton->setArrowType( mAtlas->sortAscending() ? Qt::UpArrow : Qt::DownArrow );
429 mAtlasFeatureFilterEdit->setText( mAtlas->filterExpression() );
431 mAtlasFeatureFilterCheckBox->setCheckState( mAtlas->filterFeatures() ? Qt::Checked : Qt::Unchecked );
432 mAtlasFeatureFilterEdit->setEnabled( mAtlas->filterFeatures() );
433 mAtlasFeatureFilterButton->setEnabled( mAtlas->filterFeatures() );
435 mAtlasFileFormat->setCurrentIndex( mAtlasFileFormat->findText( mLayout->customProperty( QStringLiteral(
"atlasRasterFormat" ), QStringLiteral(
"png" ) ).toString() ) );
437 blockAllSignals(
false );
440void QgsLayoutAtlasWidget::blockAllSignals(
bool b )
442 mUseAtlasCheckBox->blockSignals( b );
443 mConfigurationGroup->blockSignals( b );
444 mOutputGroup->blockSignals( b );
445 mAtlasCoverageLayerComboBox->blockSignals( b );
446 mPageNameWidget->blockSignals( b );
447 mAtlasSortExpressionWidget->blockSignals( b );
448 mAtlasFilenamePatternEdit->blockSignals( b );
449 mAtlasLimitCoverageLayerRenderCheckBox->blockSignals( b );
450 mAtlasHideCoverageCheckBox->blockSignals( b );
451 mAtlasSingleFileCheckBox->blockSignals( b );
452 mAtlasSortFeatureCheckBox->blockSignals( b );
453 mAtlasSortFeatureDirectionButton->blockSignals( b );
454 mAtlasFeatureFilterEdit->blockSignals( b );
455 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