QGIS API Documentation  2.99.0-Master (f1c3692)
qgsrasterlayersaveasdialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterlayersaveasdialog.cpp
3  ---------------------
4  begin : May 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
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 #include "qgsapplication.h"
16 #include "qgslogger.h"
17 #include "qgscoordinatetransform.h"
18 #include "qgsrasterlayer.h"
20 #include "qgsrasterdataprovider.h"
22 #include "qgsrasterrenderer.h"
23 #include "qgsrastertransparency.h"
25 #include "qgssettings.h"
26 
27 #include <gdal.h>
28 
29 #include <QFileDialog>
30 #include <QMessageBox>
31 
33  QgsRasterDataProvider *sourceProvider, const QgsRectangle &currentExtent,
34  const QgsCoordinateReferenceSystem &layerCrs, const QgsCoordinateReferenceSystem &currentCrs,
35  QWidget *parent, Qt::WindowFlags f )
36  : QDialog( parent, f )
37  , mRasterLayer( rasterLayer )
38  , mDataProvider( sourceProvider )
39  , mCurrentExtent( currentExtent )
40  , mLayerCrs( layerCrs )
41  , mCurrentCrs( currentCrs )
42  , mResolutionState( OriginalResolution )
43 {
44  setupUi( this );
45  connect( mRawModeRadioButton, &QRadioButton::toggled, this, &QgsRasterLayerSaveAsDialog::mRawModeRadioButton_toggled );
46  connect( mBrowseButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mBrowseButton_clicked );
47  connect( mSaveAsLineEdit, &QLineEdit::textChanged, this, &QgsRasterLayerSaveAsDialog::mSaveAsLineEdit_textChanged );
48  connect( mFormatComboBox, static_cast<void ( QComboBox::* )( const QString & )>( &QComboBox::currentIndexChanged ), this, &QgsRasterLayerSaveAsDialog::mFormatComboBox_currentIndexChanged );
49  connect( mResolutionRadioButton, &QRadioButton::toggled, this, &QgsRasterLayerSaveAsDialog::mResolutionRadioButton_toggled );
50  connect( mOriginalResolutionPushButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mOriginalResolutionPushButton_clicked );
51  connect( mXResolutionLineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerSaveAsDialog::mXResolutionLineEdit_textEdited );
52  connect( mYResolutionLineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerSaveAsDialog::mYResolutionLineEdit_textEdited );
53  connect( mOriginalSizePushButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mOriginalSizePushButton_clicked );
54  connect( mColumnsLineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerSaveAsDialog::mColumnsLineEdit_textEdited );
55  connect( mRowsLineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerSaveAsDialog::mRowsLineEdit_textEdited );
56  connect( mAddNoDataManuallyToolButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mAddNoDataManuallyToolButton_clicked );
57  connect( mLoadTransparentNoDataToolButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mLoadTransparentNoDataToolButton_clicked );
58  connect( mRemoveSelectedNoDataToolButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mRemoveSelectedNoDataToolButton_clicked );
59  connect( mRemoveAllNoDataToolButton, &QPushButton::clicked, this, &QgsRasterLayerSaveAsDialog::mRemoveAllNoDataToolButton_clicked );
60  connect( mTileModeCheckBox, &QCheckBox::toggled, this, &QgsRasterLayerSaveAsDialog::mTileModeCheckBox_toggled );
61  connect( mPyramidsGroupBox, &QgsCollapsibleGroupBox::toggled, this, &QgsRasterLayerSaveAsDialog::mPyramidsGroupBox_toggled );
62  mAddNoDataManuallyToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyAdd.svg" ) ) );
63  mLoadTransparentNoDataToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileOpen.svg" ) ) );
64  mRemoveSelectedNoDataToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/symbologyRemove.svg" ) ) );
65  mRemoveAllNoDataToolButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionRemove.svg" ) ) );
66 
67  mNoDataTableWidget->setColumnCount( 2 );
68  mNoDataTableWidget->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr( "From" ) ) );
69  mNoDataTableWidget->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr( "To" ) ) );
70 
71  mRawModeRadioButton_toggled( true );
72 
73  setValidators();
74 
75  toggleResolutionSize();
76 
77  //only one hardcoded format at the moment
78  QStringList myFormats;
79  myFormats << QStringLiteral( "GTiff" );
80  Q_FOREACH ( const QString &myFormat, myFormats )
81  {
82  mFormatComboBox->addItem( myFormat );
83  }
84 
85  //fill reasonable default values depending on the provider
86  if ( mDataProvider )
87  {
88  if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size )
89  {
90  setOriginalResolution();
91  int xSize = mDataProvider->xSize();
92  int ySize = mDataProvider->ySize();
93  mMaximumSizeXLineEdit->setText( QString::number( xSize ) );
94  mMaximumSizeYLineEdit->setText( QString::number( ySize ) );
95  }
96  else //wms, sometimes wcs
97  {
98  mTileModeCheckBox->setChecked( true );
99  mMaximumSizeXLineEdit->setText( QString::number( 2000 ) );
100  mMaximumSizeYLineEdit->setText( QString::number( 2000 ) );
101  }
102 
103  // setup creation option widget
104  mCreateOptionsWidget->setProvider( mDataProvider->name() );
105  if ( mDataProvider->name() == QLatin1String( "gdal" ) )
106  {
107  mCreateOptionsWidget->setFormat( myFormats[0] );
108  }
109  mCreateOptionsWidget->setRasterLayer( mRasterLayer );
110  mCreateOptionsWidget->update();
111  }
112 
113  // Only do pyramids if dealing directly with GDAL.
114  if ( mDataProvider && mDataProvider->capabilities() & QgsRasterDataProvider::BuildPyramids )
115  {
116  // setup pyramids option widget
117  // mPyramidsOptionsWidget->createOptionsWidget()->setType( QgsRasterFormatSaveOptionsWidget::ProfileLineEdit );
118  mPyramidsOptionsWidget->createOptionsWidget()->setRasterLayer( mRasterLayer );
119 
120  // TODO enable "use existing", has no effect for now, because using Create() in gdal provider
121  // if ( ! mDataProvider->hasPyramids() )
122  // mPyramidsButtonGroup->button( QgsRaster::PyramidsCopyExisting )->setEnabled( false );
123  mPyramidsUseExistingCheckBox->setEnabled( false );
124  mPyramidsUseExistingCheckBox->setVisible( false );
125 
126  populatePyramidsLevels();
127  connect( mPyramidsOptionsWidget, &QgsRasterPyramidsOptionsWidget::overviewListChanged,
128  this, &QgsRasterLayerSaveAsDialog::populatePyramidsLevels );
129  }
130  else
131  {
132  mPyramidsGroupBox->setEnabled( false );
133  }
134 
135  // restore checked state for most groupboxes (default is to restore collapsed state)
136  // create options and pyramids will be preset, if user has selected defaults in the gdal options dlg
137  mCreateOptionsGroupBox->setSaveCheckedState( true );
138  //mTilesGroupBox->setSaveCheckedState( true );
139  // don't restore nodata, it needs user input
140  // pyramids are not necessarily built every time
141 
142  mTilesGroupBox->hide();
143 
144  mCrsSelector->setLayerCrs( mLayerCrs );
145  //default to layer CRS - see https://issues.qgis.org/issues/14209 for discussion
146  mCrsSelector->setCrs( mLayerCrs );
147 
148  connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged,
149  this, &QgsRasterLayerSaveAsDialog::crsChanged );
150 
151  QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
152  if ( okButton )
153  {
154  okButton->setEnabled( false );
155  }
156 
157  connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsRasterLayerSaveAsDialog::showHelp );
158 
159  mExtentGroupBox->setOutputCrs( outputCrs() );
160  mExtentGroupBox->setOriginalExtent( mDataProvider->extent(), mLayerCrs );
161  mExtentGroupBox->setCurrentExtent( mCurrentExtent, mCurrentCrs );
162  mExtentGroupBox->setOutputExtentFromOriginal();
163  connect( mExtentGroupBox, &QgsExtentGroupBox::extentChanged, this, &QgsRasterLayerSaveAsDialog::extentChanged );
164 
165  recalcResolutionSize();
166 }
167 
168 void QgsRasterLayerSaveAsDialog::setValidators()
169 {
170  mXResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
171  mYResolutionLineEdit->setValidator( new QDoubleValidator( this ) );
172  mColumnsLineEdit->setValidator( new QIntValidator( this ) );
173  mRowsLineEdit->setValidator( new QIntValidator( this ) );
174  mMaximumSizeXLineEdit->setValidator( new QIntValidator( this ) );
175  mMaximumSizeYLineEdit->setValidator( new QIntValidator( this ) );
176 }
177 
178 void QgsRasterLayerSaveAsDialog::mBrowseButton_clicked()
179 {
180  QString fileName;
181 
182  QgsSettings settings;
183  QString dirName = mSaveAsLineEdit->text().isEmpty() ? settings.value( QStringLiteral( "UI/lastRasterFileDir" ), QDir::homePath() ).toString() : mSaveAsLineEdit->text();
184 
185  if ( mTileModeCheckBox->isChecked() )
186  {
187  Q_FOREVER
188  {
189  // TODO: would not it be better to select .vrt file instead of directory?
190  fileName = QFileDialog::getExistingDirectory( this, tr( "Select output directory" ), dirName );
191  //fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), QString(), tr( "VRT" ) + " (*.vrt *.VRT)" );
192 
193  if ( fileName.isEmpty() )
194  break; // canceled
195 
196  // Check if directory is empty
197  QDir dir( fileName );
198  QString baseName = QFileInfo( fileName ).baseName();
199  QStringList filters;
200  filters << QStringLiteral( "%1.*" ).arg( baseName );
201  QStringList files = dir.entryList( filters );
202  if ( files.isEmpty() )
203  break;
204 
205  if ( QMessageBox::warning( this, tr( "Warning" ),
206  tr( "The directory %1 contains files which will be overwritten: %2" ).arg( dir.absolutePath(), files.join( QStringLiteral( ", " ) ) ),
207  QMessageBox::Ok | QMessageBox::Cancel ) == QMessageBox::Ok )
208  break;
209 
210  fileName.clear();
211  }
212  }
213  else
214  {
215  fileName = QFileDialog::getSaveFileName( this, tr( "Select output file" ), dirName, tr( "GeoTIFF" ) + " (*.tif *.tiff *.TIF *.TIFF)" );
216 
217  // ensure the user never omits the extension from the file name
218  if ( !fileName.isEmpty() && !fileName.endsWith( QLatin1String( ".tif" ), Qt::CaseInsensitive ) && !fileName.endsWith( QLatin1String( ".tiff" ), Qt::CaseInsensitive ) )
219  {
220  fileName += QLatin1String( ".tif" );
221  }
222  }
223 
224  if ( !fileName.isEmpty() )
225  {
226  mSaveAsLineEdit->setText( fileName );
227  }
228 }
229 
230 void QgsRasterLayerSaveAsDialog::mSaveAsLineEdit_textChanged( const QString &text )
231 {
232  QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
233  if ( !okButton )
234  {
235  return;
236  }
237 
238  okButton->setEnabled( QFileInfo( text ).absoluteDir().exists() );
239 }
240 
241 
242 void QgsRasterLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( const QString &text )
243 {
244  //gdal-specific
245  if ( mDataProvider && mDataProvider->name() == QLatin1String( "gdal" ) )
246  {
247  mCreateOptionsWidget->setFormat( text );
248  mCreateOptionsWidget->update();
249  }
250 }
251 
253 {
254  return mColumnsLineEdit->text().toInt();
255 }
256 
258 {
259  return mRowsLineEdit->text().toInt();
260 }
261 
263 {
264  return mXResolutionLineEdit->text().toDouble();
265 }
266 
268 {
269  return mYResolutionLineEdit->text().toDouble();
270 }
271 
273 {
274  return mMaximumSizeXLineEdit->text().toInt();
275 }
276 
278 {
279  return mMaximumSizeYLineEdit->text().toInt();
280 }
281 
283 {
284  return mTileModeCheckBox->isChecked();
285 }
286 
288 {
289  return mAddToCanvas->isChecked();
290 }
291 
293 {
294  return mSaveAsLineEdit->text();
295 }
296 
298 {
299  return mFormatComboBox->currentText();
300 }
301 
303 {
304  return mCreateOptionsGroupBox->isChecked() ? mCreateOptionsWidget->options() : QStringList();
305 }
306 
308 {
309  return mExtentGroupBox->outputExtent();
310 }
311 
313 {
314  mFormatLabel->hide();
315  mFormatComboBox->hide();
316 }
317 
319 {
320  mSaveAsLabel->hide();
321  mSaveAsLineEdit->hide();
322  mBrowseButton->hide();
323  QPushButton *okButton = mButtonBox->button( QDialogButtonBox::Ok );
324  if ( okButton )
325  {
326  okButton->setEnabled( true );
327  }
328 }
329 
330 void QgsRasterLayerSaveAsDialog::toggleResolutionSize()
331 {
332  bool hasResolution = mDataProvider && mDataProvider->capabilities() & QgsRasterDataProvider::Size;
333 
334  bool on = mResolutionRadioButton->isChecked();
335  mXResolutionLineEdit->setEnabled( on );
336  mYResolutionLineEdit->setEnabled( on );
337  mOriginalResolutionPushButton->setEnabled( on && hasResolution );
338  mColumnsLineEdit->setEnabled( !on );
339  mRowsLineEdit->setEnabled( !on );
340  mOriginalSizePushButton->setEnabled( !on && hasResolution );
341 }
342 
343 void QgsRasterLayerSaveAsDialog::setOriginalResolution()
344 {
345  double xRes, yRes;
346 
347  if ( mDataProvider->capabilities() & QgsRasterDataProvider::Size )
348  {
349  xRes = mDataProvider->extent().width() / mDataProvider->xSize();
350  yRes = mDataProvider->extent().height() / mDataProvider->ySize();
351  }
352  else
353  {
354  // Init to something if no original resolution is available
355  xRes = yRes = mDataProvider->extent().width() / 100;
356  }
357  setResolution( xRes, yRes, mLayerCrs );
358  mResolutionState = OriginalResolution;
359  recalcSize();
360 }
361 
362 void QgsRasterLayerSaveAsDialog::setResolution( double xRes, double yRes, const QgsCoordinateReferenceSystem &srcCrs )
363 {
364  if ( srcCrs != outputCrs() )
365  {
366  // We reproject pixel rectangle from center of selected extent, of course, it gives
367  // bigger xRes,yRes than reprojected edges (envelope), it may also be that
368  // close to margins are higher resolutions (even very, too high)
369  // TODO: consider more precise resolution calculation
370 
371  QgsPointXY center = outputRectangle().center();
372  QgsCoordinateTransform ct( srcCrs, outputCrs() );
374 
375  QgsRectangle srcExtent( srsCenter.x() - xRes / 2, srsCenter.y() - yRes / 2, srsCenter.x() + xRes / 2, srsCenter.y() + yRes / 2 );
376 
377  QgsRectangle extent = ct.transform( srcExtent );
378  xRes = extent.width();
379  yRes = extent.height();
380  }
381  mXResolutionLineEdit->setText( QString::number( xRes ) );
382  mYResolutionLineEdit->setText( QString::number( yRes ) );
383 }
384 
385 void QgsRasterLayerSaveAsDialog::recalcSize()
386 {
387  QgsRectangle extent = outputRectangle();
388  int xSize = xResolution() != 0 ? static_cast<int>( std::round( extent.width() / xResolution() ) ) : 0;
389  int ySize = yResolution() != 0 ? static_cast<int>( std::round( extent.height() / yResolution() ) ) : 0;
390  mColumnsLineEdit->setText( QString::number( xSize ) );
391  mRowsLineEdit->setText( QString::number( ySize ) );
392  updateResolutionStateMsg();
393 }
394 
395 void QgsRasterLayerSaveAsDialog::setOriginalSize()
396 {
397  mColumnsLineEdit->setText( QString::number( mDataProvider->xSize() ) );
398  mRowsLineEdit->setText( QString::number( mDataProvider->ySize() ) );
399  recalcResolution();
400 }
401 
402 void QgsRasterLayerSaveAsDialog::recalcResolution()
403 {
404  QgsRectangle extent = outputRectangle();
405  double xRes = nColumns() != 0 ? extent.width() / nColumns() : 0;
406  double yRes = nRows() != 0 ? extent.height() / nRows() : 0;
407  mXResolutionLineEdit->setText( QString::number( xRes ) );
408  mYResolutionLineEdit->setText( QString::number( yRes ) );
409  updateResolutionStateMsg();
410 }
411 
412 void QgsRasterLayerSaveAsDialog::recalcResolutionSize()
413 {
414  if ( mResolutionRadioButton->isChecked() )
415  {
416  recalcSize();
417  }
418  else
419  {
420  mResolutionState = UserResolution;
421  recalcResolution();
422  }
423 }
424 
425 void QgsRasterLayerSaveAsDialog::updateResolutionStateMsg()
426 {
427  QString msg;
428  switch ( mResolutionState )
429  {
430  case OriginalResolution:
431  msg = tr( "layer" );
432  break;
433  case UserResolution:
434  msg = tr( "user defined" );
435  break;
436  default:
437  break;
438  }
439  msg = tr( "Resolution (current: %1)" ).arg( msg );
440  mResolutionGroupBox->setTitle( msg );
441 }
442 
443 void QgsRasterLayerSaveAsDialog::extentChanged()
444 {
445  // Whenever extent changes with fixed size, original resolution is lost
446  if ( mSizeRadioButton->isChecked() )
447  {
448  mResolutionState = UserResolution;
449  }
450  recalcResolutionSize();
451 }
452 
453 void QgsRasterLayerSaveAsDialog::crsChanged()
454 {
455  if ( outputCrs() != mPreviousCrs )
456  {
457  mExtentGroupBox->setOutputCrs( outputCrs() );
458 
459  // Reset resolution
460  if ( mResolutionRadioButton->isChecked() )
461  {
462  if ( mResolutionState == OriginalResolution )
463  {
464  setOriginalResolution();
465  }
466  else
467  {
468  // reset from present resolution and present crs
469  setResolution( xResolution(), yResolution(), mPreviousCrs );
470  }
471  }
472  else
473  {
474  // Size does not change, we just recalc resolution from new extent
475  recalcResolution();
476  }
477  }
478  mPreviousCrs = outputCrs();
479 }
480 
482 {
483  return mCrsSelector->crs();
484 }
485 
487 {
488  if ( mRenderedModeRadioButton->isChecked() ) return RenderedImageMode;
489  return RawDataMode;
490 }
491 
492 void QgsRasterLayerSaveAsDialog::mRawModeRadioButton_toggled( bool checked )
493 {
494  mNoDataGroupBox->setEnabled( checked && mDataProvider->bandCount() == 1 );
495 }
496 
497 void QgsRasterLayerSaveAsDialog::mAddNoDataManuallyToolButton_clicked()
498 {
499  addNoDataRow( std::numeric_limits<double>::quiet_NaN(), std::numeric_limits<double>::quiet_NaN() );
500 }
501 
502 void QgsRasterLayerSaveAsDialog::mLoadTransparentNoDataToolButton_clicked()
503 {
504  if ( !mRasterLayer->renderer() ) return;
505  const QgsRasterTransparency *rasterTransparency = mRasterLayer->renderer()->rasterTransparency();
506  if ( !rasterTransparency ) return;
507 
508  Q_FOREACH ( const QgsRasterTransparency::TransparentSingleValuePixel &transparencyPixel, rasterTransparency->transparentSingleValuePixelList() )
509  {
510  if ( transparencyPixel.percentTransparent == 100 )
511  {
512  addNoDataRow( transparencyPixel.min, transparencyPixel.max );
513  if ( transparencyPixel.min != transparencyPixel.max )
514  {
515  setNoDataToEdited( mNoDataTableWidget->rowCount() - 1 );
516  }
517  }
518  }
519 }
520 
521 void QgsRasterLayerSaveAsDialog::mRemoveSelectedNoDataToolButton_clicked()
522 {
523  mNoDataTableWidget->removeRow( mNoDataTableWidget->currentRow() );
524 }
525 
526 void QgsRasterLayerSaveAsDialog::mRemoveAllNoDataToolButton_clicked()
527 {
528  while ( mNoDataTableWidget->rowCount() > 0 )
529  {
530  mNoDataTableWidget->removeRow( 0 );
531  }
532 }
533 
534 void QgsRasterLayerSaveAsDialog::addNoDataRow( double min, double max )
535 {
536  mNoDataTableWidget->insertRow( mNoDataTableWidget->rowCount() );
537  for ( int i = 0; i < 2; i++ )
538  {
539  double value = i == 0 ? min : max;
540  QLineEdit *lineEdit = new QLineEdit();
541  lineEdit->setFrame( false );
542  lineEdit->setContentsMargins( 1, 1, 1, 1 );
543  QString valueString;
544  switch ( mRasterLayer->dataProvider()->sourceDataType( 1 ) )
545  {
546  case Qgis::Float32:
547  case Qgis::Float64:
548  lineEdit->setValidator( new QDoubleValidator( nullptr ) );
549  if ( !std::isnan( value ) )
550  {
551  valueString = QgsRasterBlock::printValue( value );
552  }
553  break;
554  default:
555  lineEdit->setValidator( new QIntValidator( nullptr ) );
556  if ( !std::isnan( value ) )
557  {
558  valueString = QString::number( static_cast<int>( value ) );
559  }
560  break;
561  }
562  lineEdit->setText( valueString );
563  mNoDataTableWidget->setCellWidget( mNoDataTableWidget->rowCount() - 1, i, lineEdit );
564 
565  adjustNoDataCellWidth( mNoDataTableWidget->rowCount() - 1, i );
566 
567  connect( lineEdit, &QLineEdit::textEdited, this, &QgsRasterLayerSaveAsDialog::noDataCellTextEdited );
568  }
569  mNoDataTableWidget->resizeColumnsToContents();
570  mNoDataTableWidget->resizeRowsToContents();
571 }
572 
573 void QgsRasterLayerSaveAsDialog::noDataCellTextEdited( const QString &text )
574 {
575  Q_UNUSED( text );
576 
577  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( sender() );
578  if ( !lineEdit ) return;
579  int row = -1;
580  int column = -1;
581  for ( int r = 0; r < mNoDataTableWidget->rowCount(); r++ )
582  {
583  for ( int c = 0; c < mNoDataTableWidget->columnCount(); c++ )
584  {
585  if ( mNoDataTableWidget->cellWidget( r, c ) == sender() )
586  {
587  row = r;
588  column = c;
589  break;
590  }
591  }
592  if ( row != -1 ) break;
593  }
594  QgsDebugMsg( QString( "row = %1 column =%2" ).arg( row ).arg( column ) );
595 
596  if ( column == 0 )
597  {
598  QLineEdit *toLineEdit = dynamic_cast<QLineEdit *>( mNoDataTableWidget->cellWidget( row, 1 ) );
599  if ( !toLineEdit ) return;
600  bool toChanged = mNoDataToEdited.value( row );
601  QgsDebugMsg( QString( "toChanged = %1" ).arg( toChanged ) );
602  if ( !toChanged )
603  {
604  toLineEdit->setText( lineEdit->text() );
605  }
606  }
607  else if ( column == 1 )
608  {
609  setNoDataToEdited( row );
610  }
611 }
612 
613 void QgsRasterLayerSaveAsDialog::mTileModeCheckBox_toggled( bool toggled )
614 {
615  if ( toggled )
616  {
617  // enable pyramids
618 
619  // Disabled (Radim), auto enabling of pyramids was making impression that
620  // we (programmers) know better what you (user) want to do,
621  // certainly auto expaning was bad experience
622 
623  //if ( ! mPyramidsGroupBox->isChecked() )
624  // mPyramidsGroupBox->setChecked( true );
625 
626  // Auto expanding mPyramidsGroupBox is bad - it auto crolls content of dialog
627  //if ( mPyramidsGroupBox->isCollapsed() )
628  // mPyramidsGroupBox->setCollapsed( false );
629  //mPyramidsOptionsWidget->checkAllLevels( true );
630 
631  // Show / hide tile options
632  mTilesGroupBox->show();
633  }
634  else
635  {
636  mTilesGroupBox->hide();
637  }
638 }
639 
640 void QgsRasterLayerSaveAsDialog::mPyramidsGroupBox_toggled( bool toggled )
641 {
642  Q_UNUSED( toggled );
643  populatePyramidsLevels();
644 }
645 
646 void QgsRasterLayerSaveAsDialog::populatePyramidsLevels()
647 {
648  QString text;
649 
650  if ( mPyramidsGroupBox->isChecked() )
651  {
652  QList<QgsRasterPyramid> myPyramidList;
653  // if use existing, get pyramids from actual layer
654  // but that's not available yet
655  if ( mPyramidsUseExistingCheckBox->isChecked() )
656  {
657  myPyramidList = mDataProvider->buildPyramidList();
658  }
659  else
660  {
661  if ( ! mPyramidsOptionsWidget->overviewList().isEmpty() )
662  myPyramidList = mDataProvider->buildPyramidList( mPyramidsOptionsWidget->overviewList() );
663  }
664  QList<QgsRasterPyramid>::iterator myRasterPyramidIterator;
665  for ( myRasterPyramidIterator = myPyramidList.begin();
666  myRasterPyramidIterator != myPyramidList.end();
667  ++myRasterPyramidIterator )
668  {
669  if ( ! mPyramidsUseExistingCheckBox->isChecked() || myRasterPyramidIterator->exists )
670  {
671  text += QString::number( myRasterPyramidIterator->xDim ) + QStringLiteral( "x" ) +
672  QString::number( myRasterPyramidIterator->yDim ) + ' ';
673  }
674  }
675  }
676 
677  mPyramidResolutionsLineEdit->setText( text.trimmed() );
678 }
679 
680 void QgsRasterLayerSaveAsDialog::setNoDataToEdited( int row )
681 {
682  if ( row >= mNoDataToEdited.size() )
683  {
684  mNoDataToEdited.resize( row + 1 );
685  }
686  mNoDataToEdited[row] = true;
687 }
688 
689 double QgsRasterLayerSaveAsDialog::noDataCellValue( int row, int column ) const
690 {
691  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( mNoDataTableWidget->cellWidget( row, column ) );
692  if ( !lineEdit || lineEdit->text().isEmpty() )
693  {
694  std::numeric_limits<double>::quiet_NaN();
695  }
696  return lineEdit->text().toDouble();
697 }
698 
699 void QgsRasterLayerSaveAsDialog::adjustNoDataCellWidth( int row, int column )
700 {
701  QLineEdit *lineEdit = dynamic_cast<QLineEdit *>( mNoDataTableWidget->cellWidget( row, column ) );
702  if ( !lineEdit ) return;
703 
704  int width = std::max( lineEdit->fontMetrics().width( lineEdit->text() ) + 10, 100 );
705  width = std::max( width, mNoDataTableWidget->columnWidth( column ) );
706 
707  lineEdit->setFixedWidth( width );
708 }
709 
711 {
712  QgsRasterRangeList noDataList;
713  if ( ! mNoDataGroupBox->isChecked() )
714  return noDataList;
715 
716  int rows = mNoDataTableWidget->rowCount();
717  noDataList.reserve( rows );
718  for ( int r = 0; r < rows; r++ )
719  {
720  QgsRasterRange noData( noDataCellValue( r, 0 ), noDataCellValue( r, 1 ) );
721  noDataList.append( noData );
722 
723  }
724  return noDataList;
725 }
726 
728 {
729  return mPyramidsGroupBox->isChecked() ? mPyramidsOptionsWidget->overviewList() : QList<int>();
730 }
731 
733 {
734  if ( ! mPyramidsGroupBox->isChecked() )
736  else if ( mPyramidsUseExistingCheckBox->isChecked() )
738  else
740 }
741 
742 bool QgsRasterLayerSaveAsDialog::validate() const
743 {
744  if ( mCreateOptionsGroupBox->isChecked() )
745  {
746  QString message = mCreateOptionsWidget->validateOptions( true, false );
747  if ( !message.isNull() )
748  return false;
749  }
750  if ( mPyramidsGroupBox->isChecked() )
751  {
752  QString message = mPyramidsOptionsWidget->createOptionsWidget()->validateOptions( true, false );
753  if ( !message.isNull() )
754  return false;
755  }
756  return true;
757 }
758 
759 void QgsRasterLayerSaveAsDialog::showHelp()
760 {
761  QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#save-layer-from-an-existing-file" ) );
762 }
virtual QgsRectangle extent() const override=0
Returns the extent of the layer.
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
static QString printValue(double value)
Print double value with all necessary significant digits.
QgsRaster::RasterBuildPyramids buildPyramidsFlag() const
void extentChanged(const QgsRectangle &r)
Emitted when the widget&#39;s extent is changed.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
#define QgsDebugMsg(str)
Definition: qgslogger.h:37
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
double y
Definition: qgspointxy.h:48
A class to represent a 2D point.
Definition: qgspointxy.h:43
virtual int ySize() const
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Raster values range container.
QgsCoordinateReferenceSystem outputCrs()
QgsRasterRenderer * renderer() const
Thirty two bit floating point (float)
Definition: qgis.h:86
const QgsRasterTransparency * rasterTransparency() const
virtual QString name() const =0
Return a provider name.
Sixty four bit floating point (double)
Definition: qgis.h:87
virtual Qgis::DataType sourceDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
QgsRasterDataProvider * dataProvider() override
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Accessor for the raster layers pyramid list.
virtual int capabilities() const
Returns a bitmask containing the supported capabilities.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:138
double x
Definition: qgspointxy.h:47
QList< QgsRasterTransparency::TransparentSingleValuePixel > transparentSingleValuePixelList() const
Accessor for transparentSingleValuePixelList.
QgsRasterLayerSaveAsDialog(QgsRasterLayer *rasterLayer, QgsRasterDataProvider *sourceProvider, const QgsRectangle &currentExtent, const QgsCoordinateReferenceSystem &layerCrs, const QgsCoordinateReferenceSystem &currentCrs, QWidget *parent=nullptr, Qt::WindowFlags f=0)
Transform from destination to source CRS.
QList< QgsRasterRange > QgsRasterRangeList
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
QgsPointXY transform(const QgsPointXY &point, TransformDirection direction=ForwardTransform) const
Transform the point from the source CRS to the destination CRS.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
This class represents a coordinate reference system (CRS).
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:34
Class for doing transforms between two map coordinate systems.
RasterBuildPyramids
Definition: qgsraster.h:74
Defines the list of pixel values to be considered as transparent or semi transparent when rendering r...
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:166
virtual int xSize() const
Get raster size.
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:145
Base class for raster data providers.