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