QGIS API Documentation 3.41.0-Master (3440c17df1d)
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#include "moc_qgsprocessingalignrasterlayerswidgetwrapper.cpp"
18
19#include <QBoxLayout>
20#include <QLineEdit>
21#include <QMessageBox>
22#include <QPushButton>
23#include <QStandardItemModel>
24#include <QToolButton>
25
26#include "qgspanelwidget.h"
30#include "qgsrasterfilewriter.h"
31#include "qgis.h"
32
34
35//
36// QgsProcessingAlignRasterLayerDetailsWidget
37//
38
39QgsProcessingAlignRasterLayerDetailsWidget::QgsProcessingAlignRasterLayerDetailsWidget( const QVariant &value, QgsProject *project )
40{
41 setupUi( this );
42
43 mOutputFileWidget->setStorageMode( QgsFileWidget::SaveFile );
44 mOutputFileWidget->setConfirmOverwrite( true );
45
46 QStringList extensions = QgsRasterFileWriter::supportedFormatExtensions();
47 QStringList filters;
48 for ( const QString &ext : extensions )
49 {
50 filters << QObject::tr( "%1 files (*.%2)" ).arg( ext.toUpper(), ext.toLower() );
51 }
52 mOutputFileWidget->setFilter( filters.join( QLatin1String( ";;" ) ) + QStringLiteral( ";;" ) + QObject::tr( "All files (*.*)" ) );
53
54 cmbResamplingMethod->addItem( tr( "Nearest Neighbour" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour ) );
55 cmbResamplingMethod->addItem( tr( "Bilinear (2x2 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Bilinear ) );
56 cmbResamplingMethod->addItem( tr( "Cubic (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Cubic ) );
57 cmbResamplingMethod->addItem( tr( "Cubic B-Spline (4x4 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_CubicSpline ) );
58 cmbResamplingMethod->addItem( tr( "Lanczos (6x6 Kernel)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Lanczos ) );
59 cmbResamplingMethod->addItem( tr( "Average" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Average ) );
60 cmbResamplingMethod->addItem( tr( "Mode" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Mode ) );
61 cmbResamplingMethod->addItem( tr( "Maximum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Max ) );
62 cmbResamplingMethod->addItem( tr( "Minimum" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Min ) );
63 cmbResamplingMethod->addItem( tr( "Median" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Median ) );
64 cmbResamplingMethod->addItem( tr( "First Quartile (Q1)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q1 ) );
65 cmbResamplingMethod->addItem( tr( "Third Quartile (Q3)" ), static_cast<int>( Qgis::GdalResampleAlgorithm::RA_Q3 ) );
66
67 mContext.setProject( project );
68
70 mInputPath = item.inputFilename;
71 mOutputFileWidget->setFilePath( item.outputFilename );
72 cmbResamplingMethod->setCurrentIndex( cmbResamplingMethod->findData( static_cast<int>( item.resampleMethod ) ) );
73 chkRescaleValues->setChecked( item.rescaleValues );
74
75 connect( mOutputFileWidget, &QgsFileWidget::fileChanged, this, &QgsPanelWidget::widgetChanged );
76 connect( cmbResamplingMethod, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsPanelWidget::widgetChanged );
77 connect( chkRescaleValues, &QCheckBox::stateChanged, this, &QgsPanelWidget::widgetChanged );
78}
79
80QVariant QgsProcessingAlignRasterLayerDetailsWidget::value() const
81{
82 QgsAlignRasterData::RasterItem item( mInputPath, mOutputFileWidget->filePath() );
83 item.resampleMethod = static_cast<Qgis::GdalResampleAlgorithm>( cmbResamplingMethod->currentData().toInt() );
84 item.rescaleValues = chkRescaleValues->isChecked();
86}
87
88
89//
90// QgsProcessingAlignRasterLayersPanelWidget
91//
92
93QgsProcessingAlignRasterLayersPanelWidget::QgsProcessingAlignRasterLayersPanelWidget(
94 const QVariant &value,
95 QgsProject *project,
96 QWidget *parent )
97 : QgsProcessingMultipleSelectionPanelWidget( QVariantList(), QVariantList(), parent )
98 , mProject( project )
99{
100 connect( listView(), &QListView::doubleClicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
101
102 QPushButton *configureLayerButton = new QPushButton( tr( "Configure Raster…" ) );
103 connect( configureLayerButton, &QPushButton::clicked, this, &QgsProcessingAlignRasterLayersPanelWidget::configureRaster );
104 buttonBox()->addButton( configureLayerButton, QDialogButtonBox::ActionRole );
105
106 // populate the list: first layers already selected, then layers from project not yet selected
107 mContext.setProject( project );
108
109 QSet<const QString > seenFiles;
110 const QVariantList valueList = value.toList();
111 for ( const QVariant &v : valueList )
112 {
114 addOption( v, titleForItem( item ), true );
115 seenFiles.insert( item.inputFilename );
116 }
117
118 const QList<QgsRasterLayer *> options = QgsProcessingUtils::compatibleRasterLayers( project );
119 for ( const QgsRasterLayer *layer : options )
120 {
121 if ( seenFiles.contains( layer->source() ) )
122 continue;
123
124 QVariantMap vm;
125 vm["inputFile"] = layer->source();
126 vm["outputFile"] = QString();
127 vm["resampleMethod"] = static_cast<int>( Qgis::GdalResampleAlgorithm::RA_NearestNeighbour );
128 vm["v"] = false;
129
130 const QString title = layer->source();
131 addOption( vm, title, false );
132 }
133}
134
135void QgsProcessingAlignRasterLayersPanelWidget::configureRaster()
136{
137 const QModelIndexList selection = listView()->selectionModel()->selectedIndexes();
138 if ( selection.size() != 1 )
139 {
140 QMessageBox::warning( this, tr( "Configure Raster" ), tr( "Please select a single layer." ) );
141 return;
142 }
143
144 QStandardItem *item = mModel->itemFromIndex( selection[0] );
145 const QVariant value = item->data( Qt::UserRole );
146
148 if ( panel && panel->dockMode() )
149 {
150 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
151 widget->setPanelTitle( tr( "Configure Raster" ) );
152 widget->buttonBox()->hide();
153
154 connect( widget, &QgsProcessingAlignRasterLayerDetailsWidget::widgetChanged, this, [ = ]()
155 {
156 setItemValue( item, widget->value() );
157 } );
158 panel->openPanel( widget );
159 }
160 else
161 {
162 QDialog dlg;
163 dlg.setWindowTitle( tr( "Configure Raster" ) );
164 QVBoxLayout *vLayout = new QVBoxLayout();
165 QgsProcessingAlignRasterLayerDetailsWidget *widget = new QgsProcessingAlignRasterLayerDetailsWidget( value, mProject );
166 vLayout->addWidget( widget );
167 connect( widget->buttonBox(), &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
168 connect( widget->buttonBox(), &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
169 dlg.setLayout( vLayout );
170 if ( dlg.exec() )
171 {
172 setItemValue( item, widget->value() );
173 }
174 }
175}
176
177void QgsProcessingAlignRasterLayersPanelWidget::setItemValue( QStandardItem *item, const QVariant &value )
178{
179 mContext.setProject( mProject );
180
182
183 item->setText( titleForItem( rasterItem ) );
184 item->setData( value, Qt::UserRole );
185}
186
187QString QgsProcessingAlignRasterLayersPanelWidget::titleForItem( const QgsAlignRasterData::RasterItem &item )
188{
189 return item.inputFilename;
190}
191
192
193//
194// QgsProcessingAlignRasterLayersWidget
195//
196
197QgsProcessingAlignRasterLayersWidget::QgsProcessingAlignRasterLayersWidget( QWidget *parent )
198 : QWidget( parent )
199{
200 QHBoxLayout *hl = new QHBoxLayout();
201 hl->setContentsMargins( 0, 0, 0, 0 );
202
203 mLineEdit = new QLineEdit();
204 mLineEdit->setEnabled( false );
205 hl->addWidget( mLineEdit, 1 );
206
207 mToolButton = new QToolButton();
208 mToolButton->setText( QString( QChar( 0x2026 ) ) );
209 hl->addWidget( mToolButton );
210
211 setLayout( hl );
212
213 updateSummaryText();
214
215 connect( mToolButton, &QToolButton::clicked, this, &QgsProcessingAlignRasterLayersWidget::showDialog );
216}
217
218void QgsProcessingAlignRasterLayersWidget::setValue( const QVariant &value )
219{
220 if ( value.isValid() )
221 mValue = value.userType() == QMetaType::Type::QVariantList ? value.toList() : QVariantList() << value;
222 else
223 mValue.clear();
224
225 updateSummaryText();
226 emit changed();
227}
228
229void QgsProcessingAlignRasterLayersWidget::setProject( QgsProject *project )
230{
231 mProject = project;
232}
233
234void QgsProcessingAlignRasterLayersWidget::showDialog()
235{
237 if ( panel && panel->dockMode() )
238 {
239 QgsProcessingAlignRasterLayersPanelWidget *widget = new QgsProcessingAlignRasterLayersPanelWidget( mValue, mProject );
240 widget->setPanelTitle( tr( "Input layers" ) );
241 connect( widget, &QgsProcessingMultipleSelectionPanelWidget::selectionChanged, this, [ = ]()
242 {
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, QgsProcessingGui::WidgetType type, QWidget *parent )
277 : QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
278{
279}
280
281QString QgsProcessingAlignRasterLayersWidgetWrapper::parameterType() const
282{
284}
285
286QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingAlignRasterLayersWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType 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 connect( mPanel, &QgsProcessingAlignRasterLayersWidget::changed, this, [ = ]
296 {
297 emit widgetValueHasChanged( this );
298 } );
299 return mPanel;
300}
301
302void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetContext( const QgsProcessingParameterWidgetContext &context )
303{
305 if ( mPanel )
306 {
307 mPanel->setProject( context.project() );
308 }
309}
310
311void QgsProcessingAlignRasterLayersWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
312{
313 Q_UNUSED( context )
314 if ( mPanel )
315 {
316 mPanel->setValue( value );
317 }
318}
319
320QVariant QgsProcessingAlignRasterLayersWidgetWrapper::widgetValue() const
321{
322 return mPanel ? mPanel->value() : QVariant();
323}
324
325QStringList QgsProcessingAlignRasterLayersWidgetWrapper::compatibleParameterTypes() const
326{
327 return QStringList()
334}
335
336QStringList QgsProcessingAlignRasterLayersWidgetWrapper::compatibleOutputTypes() const
337{
338 return QStringList()
344}
345
GdalResampleAlgorithm
Resampling algorithm to be used (equivalent to GDAL's enum GDALResampleAlg)
Definition qgis.h:5320
@ 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.
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)