QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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( const QVariant &value, QgsProject *project, QWidget *parent )
98 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
99 , mProject( project )
100{
101 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
102
103 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Raster…" ) );
104 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
105 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
106
107 // populate the list: first layers already selected, then layers from project not yet selected
108 mContext.setProject( project );
109
110 QSet<const QString> seenFiles;
111 const QVariantList valueList = value.toList();
112 for ( const QVariant &v : valueList )
113 {
115 addOption( v, titleForItem( item ), true );
116 seenFiles.insert( item.inputFilename );
117 }
118
119 const QList<QgsRasterLayer *> options = QgsProcessingUtils::compatibleRasterLayers( project );
120 for ( const QgsRasterLayer *layer : options )
121 {
122 if ( seenFiles.contains( layer->source() ) )
123 continue;
124
125 QVariantMap vm;
126 vm["inputFile"] = layer->source();
127 vm["outputFile"] = QString();
128 vm["resampleMethod"] = static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour );
129 vm["v"] = false;
130
131 const QString title = layer->source();
132 addOption( vm, title, false );
133 }
134}
135
136void QgsProcessingAlignRasterLayersPanelWidget::configureRaster()
137{
138 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
139 if ( selection.size() != 1 )
140 {
141 QMessageBox::warning( this, tr( "Configure Raster" ), tr( "Please select a single layer." ) );
142 return;
143 }
144
145 QStandardItem *item = mModel->itemFromIndex( selection[0] );
146 const QVariant value = item->data( Qt::UserRole );
147
149 if ( panel && panel->dockMode() )
150 {
151 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
152 widget->setPanelTitle( tr( "Configure Raster" ) );
153 widget->buttonBox()->hide();
154
155 connect( widget, &QgsProcessingAlignRasterLayerDetailsWidget::widgetChanged, this, [this, item, widget]() { setItemValue( item, widget->value() ); } );
156 panel->openPanel( widget );
157 }
158 else
159 {
160 QDialog dlg;
161 dlg.setWindowTitle( tr( "Configure Raster" ) );
162 QVBoxLayout *vLayout = new QVBoxLayout();
163 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
164 vLayout->addWidget( widget );
165 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
166 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
167 dlg.setLayout( vLayout );
168 if ( dlg.exec() )
169 {
170 setItemValue( item, widget->value() );
171 }
172 }
173}
174
175void QgsProcessingAlignRasterLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
176{
177 mContext.setProject( mProject );
178
180
181 item->setText( titleForItem( rasterItem ) );
182 item->setData( value, Qt::UserRole );
183}
184
185QString QgsProcessingAlignRasterLayersPanelWidget::titleForItem( const QgsAlignRasterData::RasterItem &item )
186{
187 return item.inputFilename;
188}
189
190
191//
192// QgsProcessingAlignRasterLayersWidget
193//
194
195QgsProcessingAlignRasterLayersWidget::QgsProcessingAlignRasterLayersWidget( QWidget *parent )
196 : QWidget( parent )
197{
198 QHBoxLayout *hl = new QHBoxLayout();
199 hl->setContentsMargins( 0, 0, 0, 0 );
200
201 mLineEdit = new QLineEdit();
202 mLineEdit->setEnabled( false );
203 hl->addWidget( mLineEdit, 1 );
204
205 mToolButton = new QToolButton();
206 mToolButton->setText( QString( QChar( 0x2026 ) ) );
207 hl->addWidget( mToolButton );
208
209 setLayout( hl );
210
211 updateSummaryText();
212
213 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingAlignRasterLayersWidget::showDialog );
214}
215
216void QgsProcessingAlignRasterLayersWidget::setValue( const QVariant &value )
217{
218 if ( value.isValid() )
219 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
220 else
221 mValue.clear();
222
223 updateSummaryText();
224 emit changed();
225}
226
227void QgsProcessingAlignRasterLayersWidget::setProject( QgsProject *project )
228{
229 mProject = project;
230}
231
232void QgsProcessingAlignRasterLayersWidget::showDialog()
233{
235 if ( panel && panel->dockMode() )
236 {
237 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
238 widget->setPanelTitle( tr( "Input layers" ) );
239 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [this, widget]() { setValue( widget->selectedOptions() ); } );
240 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::acceptClicked, widget, &QgsPanelWidget::acceptPanel );
241 panel->openPanel( widget );
242 }
243 else
244 {
245 QDialog dlg;
246 dlg.setWindowTitle( tr( "Input layers" ) );
247 QVBoxLayout *vLayout = new QVBoxLayout();
248 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
249 vLayout->addWidget( widget );
250 widget->buttonBox()->addButton( QDialogButtonBox::Cancel );
251 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
252 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
253 dlg.setLayout( vLayout );
254 if ( dlg.exec() )
255 {
256 setValue( widget->selectedOptions() );
257 }
258 }
259}
260
261void QgsProcessingAlignRasterLayersWidget::updateSummaryText()
262{
263 mLineEdit->setText( tr( "%n raster layer(s) selected", nullptr, mValue.count() ) );
264}
265
266
267//
268// QgsProcessingAlignRasterLayersWidgetWrapper
269//
270
271QgsProcessingAlignRasterLayersWidgetWrapper::QgsProcessingAlignRasterLayersWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type, QWidget *parent )
272 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
273{}
274
275QString QgsProcessingAlignRasterLayersWidgetWrapper::parameterType() const
276{
278}
279
280QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAlignRasterLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, Qgis::ProcessingMode type )
281{
282 return new QgsProcessingAlignRasterLayersWidgetWrapper( parameter, type );
283}
284
285QWidget *QgsProcessingAlignRasterLayersWidgetWrapper::createWidget()
286{
287 mPanel = new QgsProcessingAlignRasterLayersWidget( nullptr );
288 mPanel->setProject( widgetContext().project() );
289 if ( parameterDefinition() )
290 {
291 mPanel->setToolTip( parameterDefinition()->toolTip() );
292 }
293 connect( mPanel, &QgsProcessingAlignRasterLayersWidget::changed, this, [this] { emit widgetValueHasChanged( this ); } );
294 return mPanel;
295}
296
297void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
298{
300 if ( mPanel )
301 {
302 mPanel->setProject( context.project() );
303 }
304}
305
306void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
307{
308 Q_UNUSED( context )
309 if ( mPanel )
310 {
311 mPanel->setValue( value );
312 }
313}
314
315QVariant QgsProcessingAlignRasterLayersWidgetWrapper::widgetValue() const
316{
317 return mPanel ? mPanel->value() : QVariant();
318}
319
ProcessingMode
Types of modes which Processing widgets can be created for.
Definition qgis.h:3786
GdalResampleAlgorithm
Resampling algorithm to be used (equivalent to GDAL's enum GDALResampleAlg).
Definition qgis.h:6078
@ RA_Lanczos
Lanczos windowed sinc interpolation (6x6 kernel).
Definition qgis.h:6083
@ RA_Q3
Third quartile (selects the third quartile of all non-NODATA contributing pixels).
Definition qgis.h:6090
@ RA_CubicSpline
Cubic B-Spline Approximation (4x4 kernel).
Definition qgis.h:6082
@ RA_Q1
First quartile (selects the first quartile of all non-NODATA contributing pixels).
Definition qgis.h:6089
@ RA_Min
Minimum (selects the minimum of all non-NODATA contributing pixels).
Definition qgis.h:6087
@ RA_Median
Median (selects the median of all non-NODATA contributing pixels).
Definition qgis.h:6088
@ RA_NearestNeighbour
Nearest neighbour (select on one input pixel).
Definition qgis.h:6079
@ RA_Average
Average (computes the average of all non-NODATA contributing pixels).
Definition qgis.h:6084
@ RA_Max
Maximum (selects the maximum of all non-NODATA contributing pixels).
Definition qgis.h:6086
@ RA_Bilinear
Bilinear (2x2 kernel).
Definition qgis.h:6080
@ RA_Mode
Mode (selects the value which appears most often of all the sampled points).
Definition qgis.h:6085
@ RA_Cubic
Cubic Convolution Approximation (4x4 kernel).
Definition qgis.h:6081
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)