QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgsprocessingalignrasterlayerswidgetwrapper.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprocessingalignrasterlayerswidgetwrapper.cpp
3 ---------------------
4 Date : July 2023
5 Copyright : (C) 2023 by Alexander Bruy
6 Email : alexander dot bruy at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17
18#include <QBoxLayout>
19#include <QLineEdit>
20#include <QMessageBox>
21#include <QPushButton>
22#include <QStandardItemModel>
23#include <QToolButton>
24
25#include "qgspanelwidget.h"
29#include "qgsrasterfilewriter.h"
30#include "qgis.h"
31
33
34//
35// QgsProcessingAlignRasterLayerDetailsWidget
36//
37
38QgsProcessingAlignRasterLayerDetailsWidget::QgsProcessingAlignRasterLayerDetailsWidget( const QVariant &value, QgsProject *project )
39{
40 setupUi( this );
41
42 mOutputFileWidget->setStorageMode( QgsFileWidget::SaveFile );
43 mOutputFileWidget->setConfirmOverwrite( true );
44
45 QStringList extensions = QgsRasterFileWriter::supportedFormatExtensions();
46 QStringList filters;
47 for ( const QString &ext : extensions )
48 {
49 filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
50 }
51 mOutputFileWidget->setFilter( filters.join( QLatin1String( ";;" ) ) + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) );
52
53 cmbResamplingMethod->addItem( tr( "Nearest Neighbour" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour ) );
54 cmbResamplingMethod->addItem( tr( "Bilinear (2x2 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Bilinear ) );
55 cmbResamplingMethod->addItem( tr( "Cubic (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Cubic ) );
56 cmbResamplingMethod->addItem( tr( "Cubic B-Spline (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_CubicSpline ) );
57 cmbResamplingMethod->addItem( tr( "Lanczos (6x6 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Lanczos ) );
58 cmbResamplingMethod->addItem( tr( "Average" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Average ) );
59 cmbResamplingMethod->addItem( tr( "Mode" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Mode ) );
60 cmbResamplingMethod->addItem( tr( "Maximum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Max ) );
61 cmbResamplingMethod->addItem( tr( "Minimum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Min ) );
62 cmbResamplingMethod->addItem( tr( "Median" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Median ) );
63 cmbResamplingMethod->addItem( tr( "First Quartile (Q1)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q1 ) );
64 cmbResamplingMethod->addItem( tr( "Third Quartile (Q3)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q3 ) );
65
66 mContext.setProject( project );
67
69 mInputPath = item.inputFilename;
70 mOutputFileWidget->setFilePath( item.outputFilename );
71 cmbResamplingMethod->setCurrentIndex( cmbResamplingMethod->findData( static_cast<int>( item.resampleMethod ) ) );
72 chkRescaleValues->setChecked( item.rescaleValues );
73
74 connect( mOutputFileWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
75 connect( cmbResamplingMethod, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
76 connect( chkRescaleValues, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
77}
78
79QVariant QgsProcessingAlignRasterLayerDetailsWidget::value() const
80{
81 QgsAlignRasterData::RasterItem item( mInputPath, mOutputFileWidget->filePath() );
82 item.resampleMethod = static_cast<Qgis::GdalResampleAlgorithm>( cmbResamplingMethod->currentData().toInt() );
83 item.rescaleValues = chkRescaleValues->isChecked();
85}
86
87
88//
89// QgsProcessingAlignRasterLayersPanelWidget
90//
91
92QgsProcessingAlignRasterLayersPanelWidget::QgsProcessingAlignRasterLayersPanelWidget(
93 const QVariant &value,
94 QgsProject *project,
95 QWidget *parent )
96 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
97 , mProject( project )
98{
99 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
100
101 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Raster…" ) );
102 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
103 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
104
105 // populate the list: first layers already selected, then layers from project not yet selected
106 mContext.setProject( project );
107
108 QSet<const QString > seenFiles;
109 const QVariantList valueList = value.toList();
110 for ( const QVariant &v : valueList )
111 {
113 addOption( v, titleForItem( item ), true );
114 seenFiles.insert( item.inputFilename );
115 }
116
117 const QList<QgsRasterLayer *> options = QgsProcessingUtils::compatibleRasterLayers( project );
118 for ( const QgsRasterLayer *layer : options )
119 {
120 if ( seenFiles.contains( layer->source() ) )
121 continue;
122
123 QVariantMap vm;
124 vm["inputFile"] = layer->source();
125 vm["outputFile"] = QString();
126 vm["resampleMethod"] = static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour );
127 vm["v"] = false;
128
129 const QString title = layer->source();
130 addOption( vm, title, false );
131 }
132}
133
134void QgsProcessingAlignRasterLayersPanelWidget::configureRaster()
135{
136 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
137 if ( selection.size() != 1 )
138 {
139 QMessageBox::warning( this, tr( "Configure Raster" ), tr( "Please select a single layer." ) );
140 return;
141 }
142
143 QStandardItem *item = mModel->itemFromIndex( selection[0] );
144 const QVariant value = item->data( Qt::UserRole );
145
147 if ( panel && panel->dockMode() )
148 {
149 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
150 widget->setPanelTitle( tr( "Configure Raster" ) );
151 widget->buttonBox()->hide();
152
153 connect( widget, &QgsProcessingAlignRasterLayerDetailsWidget::widgetChanged, this, [ = ]()
154 {
155 setItemValue( item, widget->value() );
156 } );
157 panel->openPanel( widget );
158 }
159 else
160 {
161 QDialog dlg;
162 dlg.setWindowTitle( tr( "Configure Raster" ) );
163 QVBoxLayout *vLayout = new QVBoxLayout();
164 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
165 vLayout->addWidget( widget );
166 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
167 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
168 dlg.setLayout( vLayout );
169 if ( dlg.exec() )
170 {
171 setItemValue( item, widget->value() );
172 }
173 }
174}
175
176void QgsProcessingAlignRasterLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
177{
178 mContext.setProject( mProject );
179
181
182 item->setText( titleForItem( rasterItem ) );
183 item->setData( value, Qt::UserRole );
184}
185
186QString QgsProcessingAlignRasterLayersPanelWidget::titleForItem( const QgsAlignRasterData::RasterItem &item )
187{
188 return item.inputFilename;
189}
190
191
192//
193// QgsProcessingAlignRasterLayersWidget
194//
195
196QgsProcessingAlignRasterLayersWidget::QgsProcessingAlignRasterLayersWidget( QWidget *parent )
197 : QWidget( parent )
198{
199 QHBoxLayout *hl = new QHBoxLayout();
200 hl->setContentsMargins( 0, 0, 0, 0 );
201
202 mLineEdit = new QLineEdit();
203 mLineEdit->setEnabled( false );
204 hl->addWidget( mLineEdit, 1 );
205
206 mToolButton = new QToolButton();
207 mToolButton->setText( QString( QChar( 0x2026 ) ) );
208 hl->addWidget( mToolButton );
209
210 setLayout( hl );
211
212 updateSummaryText();
213
214 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingAlignRasterLayersWidget::showDialog );
215}
216
217void QgsProcessingAlignRasterLayersWidget::setValue( const QVariant &value )
218{
219 if ( value.isValid() )
220 mValue = value.type() == QVariant::List ? value.toList() : QVariantList() << value;
221 else
222 mValue.clear();
223
224 updateSummaryText();
225 emit changed();
226}
227
228void QgsProcessingAlignRasterLayersWidget::setProject( QgsProject *project )
229{
230 mProject = project;
231}
232
233void QgsProcessingAlignRasterLayersWidget::showDialog()
234{
236 if ( panel && panel->dockMode() )
237 {
238 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
239 widget->setPanelTitle( tr( "Input layers" ) );
240 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
241 {
242 setValue( widget->selectedOptions() );
243 } );
244 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
245 panel->openPanel( widget );
246 }
247 else
248 {
249 QDialog dlg;
250 dlg.setWindowTitle( tr( "Input layers" ) );
251 QVBoxLayout *vLayout = new QVBoxLayout();
252 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
253 vLayout->addWidget( widget );
254 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
255 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
256 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
257 dlg.setLayout( vLayout );
258 if ( dlg.exec() )
259 {
260 setValue( widget->selectedOptions() );
261 }
262 }
263}
264
265void QgsProcessingAlignRasterLayersWidget::updateSummaryText()
266{
267 mLineEdit->setText( tr( "%n raster layer(s) selected", nullptr, mValue.count() ) );
268}
269
270
271//
272// QgsProcessingAlignRasterLayersWidgetWrapper
273//
274
275QgsProcessingAlignRasterLayersWidgetWrapper::QgsProcessingAlignRasterLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
276 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
277{
278}
279
280QString QgsProcessingAlignRasterLayersWidgetWrapper::parameterType() const
281{
283}
284
285QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAlignRasterLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
286{
287 return new QgsProcessingAlignRasterLayersWidgetWrapper( parameter, type );
288}
289
290QWidget *QgsProcessingAlignRasterLayersWidgetWrapper::createWidget()
291{
292 mPanel = new QgsProcessingAlignRasterLayersWidget( nullptr );
293 mPanel->setProject( widgetContext().project() );
294 connect( mPanel, &QgsProcessingAlignRasterLayersWidget::changed, this, [ = ]
295 {
296 emit widgetValueHasChanged( this );
297 } );
298 return mPanel;
299}
300
301void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
302{
304 if ( mPanel )
305 {
306 mPanel->setProject( context.project() );
307 }
308}
309
310void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
311{
312 Q_UNUSED( context )
313 if ( mPanel )
314 {
315 mPanel->setValue( value );
316 }
317}
318
319QVariant QgsProcessingAlignRasterLayersWidgetWrapper::widgetValue() const
320{
321 return mPanel ? mPanel->value() : QVariant();
322}
323
324QStringList QgsProcessingAlignRasterLayersWidgetWrapper::compatibleParameterTypes() const
325{
326 return QStringList()
333}
334
335QStringList QgsProcessingAlignRasterLayersWidgetWrapper::compatibleOutputTypes() const
336{
337 return QStringList()
343}
344
GdalResampleAlgorithm
Resampling algorithm to be used (equivalent to GDAL's enum GDALResampleAlg)
Definition: qgis.h:4642
@ RA_Lanczos
Lanczos windowed sinc interpolation (6x6 kernel)
@ RA_Q3
Third quartile (selects the third quartile of all non-NODATA contributing pixels)
@ RA_CubicSpline
Cubic B-Spline Approximation (4x4 kernel)
@ RA_Q1
First quartile (selects the first quartile of all non-NODATA contributing pixels)
@ RA_Min
Minimum (selects the minimum of all non-NODATA contributing pixels)
@ RA_Median
Median (selects the median of all non-NODATA contributing pixels)
@ RA_NearestNeighbour
Nearest neighbour (select on one input pixel)
@ RA_Average
Average (computes the average of all non-NODATA contributing pixels)
@ RA_Max
Maximum (selects the maximum of all non-NODATA contributing pixels)
@ RA_Bilinear
Bilinear (2x2 kernel)
@ RA_Mode
Mode (selects the value which appears most often of all the sampled points)
@ RA_Cubic
Cubic Convolution Approximation (4x4 kernel)
A widget wrapper for Processing parameter value widgets.
virtual void setWidgetContext(const QgsProcessingParameterWidgetContext &context)
Sets the context in which the Processing parameter widget is shown, e.g., the parent model algorithm,...
@ SaveFile
Select a single new or pre-existing file.
Definition: qgsfilewidget.h:71
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
void widgetChanged()
Emitted when the widget state changes.
void acceptPanel()
Accept the panel.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
Contains information about the context in which a processing algorithm is executed.
WidgetType
Types of dialogs which Processing widgets can be created for.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the output class.
static QString typeName()
Returns the type name for the parameter class.
static QgsAlignRasterData::RasterItem variantMapAsItem(const QVariantMap &layerVariantMap, QgsProcessingContext &context)
Converts a QVariant value (a QVariantMap) to a single input layer.
static QVariantMap itemAsVariantMap(const QgsAlignRasterData::RasterItem &item)
Converts a single input layer to QVariant representation (a QVariantMap)
Base class for the definition of processing parameters.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
static QString typeName()
Returns the type name for the parameter class.
Contains settings which reflect the context in which a Processing parameter widget is shown,...
QgsProject * project() const
Returns the project associated with the widget.
static QList< QgsRasterLayer * > compatibleRasterLayers(QgsProject *project, bool sort=true)
Returns a list of raster layers from a project which are compatible with the processing framework.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition: qgsproject.h:107
static QStringList supportedFormatExtensions(RasterFormatOptions options=SortRecommended)
Returns a list of file extensions for supported formats.
Represents a raster layer.
Definition of one raster layer for alignment.
Qgis::GdalResampleAlgorithm resampleMethod
resampling method to be used
bool rescaleValues
rescaling of values according to the change of pixel size
QString inputFilename
filename of the source raster
QString outputFilename
filename of the newly created aligned raster (will be overwritten if exists already)