QGIS API Documentation 3.99.0-Master (09f76ad7019)
Loading...
Searching...
No Matches
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 "qgis.h"
19#include "qgspanelwidget.h"
23#include "qgsrasterfilewriter.h"
24
25#include <QBoxLayout>
26#include <QLineEdit>
27#include <QMessageBox>
28#include <QPushButton>
29#include <QStandardItemModel>
30#include <QString>
31#include <QToolButton>
32
33#include "moc_qgsprocessingalignrasterlayerswidgetwrapper.cpp"
34
35using namespace Qt::StringLiterals;
36
38
39//
40// QgsProcessingAlignRasterLayerDetailsWidget
41//
42
43QgsProcessingAlignRasterLayerDetailsWidget::QgsProcessingAlignRasterLayerDetailsWidget( const QVariant &value, QgsProject *project )
44{
45 setupUi( this );
46
47 mOutputFileWidget->setStorageMode( QgsFileWidget::SaveFile );
48 mOutputFileWidget->setConfirmOverwrite( true );
49
50 QStringList extensions = QgsRasterFileWriter::supportedFormatExtensions();
51 QStringList filters;
52 for ( const QString &ext : extensions )
53 {
54 filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
55 }
56 mOutputFileWidget->setFilter( filters.join( ";;"_L1 ) + u";;"_s + QObject::tr( "All files (*.*)" ) );
57
58 cmbResamplingMethod->addItem( tr( "Nearest Neighbour" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour ) );
59 cmbResamplingMethod->addItem( tr( "Bilinear (2x2 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Bilinear ) );
60 cmbResamplingMethod->addItem( tr( "Cubic (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Cubic ) );
61 cmbResamplingMethod->addItem( tr( "Cubic B-Spline (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_CubicSpline ) );
62 cmbResamplingMethod->addItem( tr( "Lanczos (6x6 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Lanczos ) );
63 cmbResamplingMethod->addItem( tr( "Average" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Average ) );
64 cmbResamplingMethod->addItem( tr( "Mode" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Mode ) );
65 cmbResamplingMethod->addItem( tr( "Maximum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Max ) );
66 cmbResamplingMethod->addItem( tr( "Minimum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Min ) );
67 cmbResamplingMethod->addItem( tr( "Median" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Median ) );
68 cmbResamplingMethod->addItem( tr( "First Quartile (Q1)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q1 ) );
69 cmbResamplingMethod->addItem( tr( "Third Quartile (Q3)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q3 ) );
70
71 mContext.setProject( project );
72
74 mInputPath = item.inputFilename;
75 mOutputFileWidget->setFilePath( item.outputFilename );
76 cmbResamplingMethod->setCurrentIndex( cmbResamplingMethod->findData( static_cast<int>( item.resampleMethod ) ) );
77 chkRescaleValues->setChecked( item.rescaleValues );
78
79 connect( mOutputFileWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
80 connect( cmbResamplingMethod, qOverload<int>( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
81 connect( chkRescaleValues, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
82}
83
84QVariant QgsProcessingAlignRasterLayerDetailsWidget::value() const
85{
86 QgsAlignRasterData::RasterItem item( mInputPath, mOutputFileWidget->filePath() );
87 item.resampleMethod = static_cast<Qgis::GdalResampleAlgorithm>( cmbResamplingMethod->currentData().toInt() );
88 item.rescaleValues = chkRescaleValues->isChecked();
90}
91
92
93//
94// QgsProcessingAlignRasterLayersPanelWidget
95//
96
97QgsProcessingAlignRasterLayersPanelWidget::QgsProcessingAlignRasterLayersPanelWidget(
98 const QVariant &value,
99 QgsProject *project,
100 QWidget *parent
101)
102 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
103 , mProject( project )
104{
105 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
106
107 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Raster…" ) );
108 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
109 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
110
111 // populate the list: first layers already selected, then layers from project not yet selected
112 mContext.setProject( project );
113
114 QSet<const QString> seenFiles;
115 const QVariantList valueList = value.toList();
116 for ( const QVariant &v : valueList )
117 {
119 addOption( v, titleForItem( item ), true );
120 seenFiles.insert( item.inputFilename );
121 }
122
123 const QList<QgsRasterLayer *> options = QgsProcessingUtils::compatibleRasterLayers( project );
124 for ( const QgsRasterLayer *layer : options )
125 {
126 if ( seenFiles.contains( layer->source() ) )
127 continue;
128
129 QVariantMap vm;
130 vm["inputFile"] = layer->source();
131 vm["outputFile"] = QString();
132 vm["resampleMethod"] = static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour );
133 vm["v"] = false;
134
135 const QString title = layer->source();
136 addOption( vm, title, false );
137 }
138}
139
140void QgsProcessingAlignRasterLayersPanelWidget::configureRaster()
141{
142 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
143 if ( selection.size() != 1 )
144 {
145 QMessageBox::warning( this, tr( "Configure Raster" ), tr( "Please select a single layer." ) );
146 return;
147 }
148
149 QStandardItem *item = mModel->itemFromIndex( selection[0] );
150 const QVariant value = item->data( Qt::UserRole );
151
153 if ( panel && panel->dockMode() )
154 {
155 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
156 widget->setPanelTitle( tr( "Configure Raster" ) );
157 widget->buttonBox()->hide();
158
159 connect( widget, &QgsProcessingAlignRasterLayerDetailsWidget::widgetChanged, this, [this, item, widget]() {
160 setItemValue( item, widget->value() );
161 } );
162 panel->openPanel( widget );
163 }
164 else
165 {
166 QDialog dlg;
167 dlg.setWindowTitle( tr( "Configure Raster" ) );
168 QVBoxLayout *vLayout = new QVBoxLayout();
169 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
170 vLayout->addWidget( widget );
171 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
172 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
173 dlg.setLayout( vLayout );
174 if ( dlg.exec() )
175 {
176 setItemValue( item, widget->value() );
177 }
178 }
179}
180
181void QgsProcessingAlignRasterLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
182{
183 mContext.setProject( mProject );
184
186
187 item->setText( titleForItem( rasterItem ) );
188 item->setData( value, Qt::UserRole );
189}
190
191QString QgsProcessingAlignRasterLayersPanelWidget::titleForItem( const QgsAlignRasterData::RasterItem &item )
192{
193 return item.inputFilename;
194}
195
196
197//
198// QgsProcessingAlignRasterLayersWidget
199//
200
201QgsProcessingAlignRasterLayersWidget::QgsProcessingAlignRasterLayersWidget( QWidget *parent )
202 : QWidget( parent )
203{
204 QHBoxLayout *hl = new QHBoxLayout();
205 hl->setContentsMargins( 0, 0, 0, 0 );
206
207 mLineEdit = new QLineEdit();
208 mLineEdit->setEnabled( false );
209 hl->addWidget( mLineEdit, 1 );
210
211 mToolButton = new QToolButton();
212 mToolButton->setText( QString( QChar( 0x2026 ) ) );
213 hl->addWidget( mToolButton );
214
215 setLayout( hl );
216
217 updateSummaryText();
218
219 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingAlignRasterLayersWidget::showDialog );
220}
221
222void QgsProcessingAlignRasterLayersWidget::setValue( const QVariant &value )
223{
224 if ( value.isValid() )
225 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
226 else
227 mValue.clear();
228
229 updateSummaryText();
230 emit changed();
231}
232
233void QgsProcessingAlignRasterLayersWidget::setProject( QgsProject *project )
234{
235 mProject = project;
236}
237
238void QgsProcessingAlignRasterLayersWidget::showDialog()
239{
241 if ( panel && panel->dockMode() )
242 {
243 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
244 widget->setPanelTitle( tr( "Input layers" ) );
245 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() {
246 setValue( widget->selectedOptions() );
247 } );
248 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
249 panel->openPanel( widget );
250 }
251 else
252 {
253 QDialog dlg;
254 dlg.setWindowTitle( tr( "Input layers" ) );
255 QVBoxLayout *vLayout = new QVBoxLayout();
256 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
257 vLayout->addWidget( widget );
258 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
259 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
260 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
261 dlg.setLayout( vLayout );
262 if ( dlg.exec() )
263 {
264 setValue( widget->selectedOptions() );
265 }
266 }
267}
268
269void QgsProcessingAlignRasterLayersWidget::updateSummaryText()
270{
271 mLineEdit->setText( tr( "%n raster layer(s) selected", nullptr, mValue.count() ) );
272}
273
274
275//
276// QgsProcessingAlignRasterLayersWidgetWrapper
277//
278
279QgsProcessingAlignRasterLayersWidgetWrapper::QgsProcessingAlignRasterLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
280 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
281{
282}
283
284QString QgsProcessingAlignRasterLayersWidgetWrapper::parameterType() const
285{
287}
288
289QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAlignRasterLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
290{
291 return new QgsProcessingAlignRasterLayersWidgetWrapper( parameter, type );
292}
293
294QWidget *QgsProcessingAlignRasterLayersWidgetWrapper::createWidget()
295{
296 mPanel = new QgsProcessingAlignRasterLayersWidget( nullptr );
297 mPanel->setProject( widgetContext().project() );
298 if ( parameterDefinition() )
299 {
300 mPanel->setToolTip( parameterDefinition()->toolTip() );
301 }
302 connect( mPanel, &QgsProcessingAlignRasterLayersWidget::changed, this, [this] {
303 emit widgetValueHasChanged( this );
304 } );
305 return mPanel;
306}
307
308void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
309{
311 if ( mPanel )
312 {
313 mPanel->setProject( context.project() );
314 }
315}
316
317void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
318{
319 Q_UNUSED( context )
320 if ( mPanel )
321 {
322 mPanel->setValue( value );
323 }
324}
325
326QVariant QgsProcessingAlignRasterLayersWidgetWrapper::widgetValue() const
327{
328 return mPanel ? mPanel->value() : QVariant();
329}
330
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3742
GdalResampleAlgorithm
Resampling algorithm to be used (equivalent to GDAL's enum GDALResampleAlg).
Definition qgis.h:6023
@ RA_Lanczos
Lanczos windowed sinc interpolation (6x6 kernel).
Definition qgis.h:6028
@ RA_Q3
Third quartile (selects the third quartile of all non-NODATA contributing pixels).
Definition qgis.h:6035
@ RA_CubicSpline
Cubic B-Spline Approximation (4x4 kernel).
Definition qgis.h:6027
@ RA_Q1
First quartile (selects the first quartile of all non-NODATA contributing pixels).
Definition qgis.h:6034
@ RA_Min
Minimum (selects the minimum of all non-NODATA contributing pixels).
Definition qgis.h:6032
@ RA_Median
Median (selects the median of all non-NODATA contributing pixels).
Definition qgis.h:6033
@ RA_NearestNeighbour
Nearest neighbour (select on one input pixel).
Definition qgis.h:6024
@ RA_Average
Average (computes the average of all non-NODATA contributing pixels).
Definition qgis.h:6029
@ RA_Max
Maximum (selects the maximum of all non-NODATA contributing pixels).
Definition qgis.h:6031
@ RA_Bilinear
Bilinear (2x2 kernel).
Definition qgis.h:6025
@ RA_Mode
Mode (selects the value which appears most often of all the sampled points).
Definition qgis.h:6030
@ RA_Cubic
Cubic Convolution Approximation (4x4 kernel).
Definition qgis.h:6026
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.
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 an 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 ...
bool dockMode() const
Returns the dock mode state.
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.
Contains information about the context in which a processing algorithm is executed.
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.
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:113
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)