QGIS API Documentation  3.8.0-Zanzibar (11aff65)
qgsrasterformatsaveoptionswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrasterformatsaveoptionswidget.cpp
3  -------------------
4  begin : July 2012
5  copyright : (C) 2012 by Etienne Tourigny
6  email : etourigny dot dev at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 #include "qgslogger.h"
20 #include "qgsdialog.h"
21 #include "qgsrasterlayer.h"
22 #include "qgsproviderregistry.h"
23 #include "qgsrasterdataprovider.h"
24 #include "qgssettings.h"
25 
26 #include <QInputDialog>
27 #include <QMessageBox>
28 #include <QTextEdit>
29 #include <QMouseEvent>
30 #include <QMenu>
31 
32 
33 QMap< QString, QStringList > QgsRasterFormatSaveOptionsWidget::sBuiltinProfiles;
34 
35 static const QString PYRAMID_JPEG_YCBCR_COMPRESSION( QStringLiteral( "JPEG_QUALITY_OVERVIEW=75 COMPRESS_OVERVIEW=JPEG PHOTOMETRIC_OVERVIEW=YCBCR INTERLEAVE_OVERVIEW=PIXEL" ) );
36 static const QString PYRAMID_JPEG_COMPRESSION( QStringLiteral( "JPEG_QUALITY_OVERVIEW=75 COMPRESS_OVERVIEW=JPEG INTERLEAVE_OVERVIEW=PIXEL" ) );
37 
39  QgsRasterFormatSaveOptionsWidget::Type type, const QString &provider )
40  : QWidget( parent )
41  , mFormat( format )
42  , mProvider( provider )
43 {
44  setupUi( this );
45  connect( mProfileNewButton, &QPushButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::mProfileNewButton_clicked );
46  connect( mProfileDeleteButton, &QPushButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::mProfileDeleteButton_clicked );
47  connect( mProfileResetButton, &QPushButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::mProfileResetButton_clicked );
48  connect( mOptionsAddButton, &QPushButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::mOptionsAddButton_clicked );
49  connect( mOptionsDeleteButton, &QPushButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::mOptionsDeleteButton_clicked );
50  connect( mOptionsLineEdit, &QLineEdit::editingFinished, this, &QgsRasterFormatSaveOptionsWidget::mOptionsLineEdit_editingFinished );
51 
52  setType( type );
53 
54  if ( sBuiltinProfiles.isEmpty() )
55  {
56  // key=profileKey values=format,profileName,options
57  sBuiltinProfiles[ QStringLiteral( "z_adefault" )] = ( QStringList() << QString() << tr( "Default" ) << QString() );
58 
59  // these GTiff profiles are based on Tim's benchmarks at
60  // http://linfiniti.com/2011/05/gdal-efficiency-of-various-compression-algorithms/
61  // big: no compression | medium: reasonable size/speed tradeoff | small: smallest size
62  sBuiltinProfiles[ QStringLiteral( "z_gtiff_1big" )] =
63  ( QStringList() << QStringLiteral( "GTiff" ) << tr( "No Compression" )
64  << QStringLiteral( "COMPRESS=NONE BIGTIFF=IF_NEEDED" ) );
65  sBuiltinProfiles[ QStringLiteral( "z_gtiff_2medium" )] =
66  ( QStringList() << QStringLiteral( "GTiff" ) << tr( "Low Compression" )
67  << QStringLiteral( "COMPRESS=PACKBITS" ) );
68  sBuiltinProfiles[ QStringLiteral( "z_gtiff_3small" )] =
69  ( QStringList() << QStringLiteral( "GTiff" ) << tr( "High Compression" )
70  << QStringLiteral( "COMPRESS=DEFLATE PREDICTOR=2 ZLEVEL=9" ) );
71  sBuiltinProfiles[ QStringLiteral( "z_gtiff_4jpeg" )] =
72  ( QStringList() << QStringLiteral( "GTiff" ) << tr( "JPEG Compression" )
73  << QStringLiteral( "COMPRESS=JPEG JPEG_QUALITY=75" ) );
74 
75  // overview compression schemes for GTiff format, see
76  // http://www.gdal.org/gdaladdo.html and http://www.gdal.org/frmt_gtiff.html
77  // TODO - should we offer GDAL_TIFF_OVR_BLOCKSIZE option here or in QgsRasterPyramidsOptionsWidget ?
78  sBuiltinProfiles[ QStringLiteral( "z__pyramids_gtiff_1big" )] =
79  ( QStringList() << QStringLiteral( "_pyramids" ) << tr( "No Compression" )
80  << QStringLiteral( "COMPRESS_OVERVIEW=NONE BIGTIFF_OVERVIEW=IF_NEEDED" ) );
81  sBuiltinProfiles[ QStringLiteral( "z__pyramids_gtiff_2medium" )] =
82  ( QStringList() << QStringLiteral( "_pyramids" ) << tr( "Low Compression" )
83  << QStringLiteral( "COMPRESS_OVERVIEW=PACKBITS" ) );
84  sBuiltinProfiles[ QStringLiteral( "z__pyramids_gtiff_3small" )] =
85  ( QStringList() << QStringLiteral( "_pyramids" ) << tr( "High Compression" )
86  << QStringLiteral( "COMPRESS_OVERVIEW=DEFLATE PREDICTOR_OVERVIEW=2 ZLEVEL=9" ) ); // how to set zlevel?
87  sBuiltinProfiles[ QStringLiteral( "z__pyramids_gtiff_4jpeg" )] =
88  ( QStringList() << QStringLiteral( "_pyramids" ) << tr( "JPEG Compression" )
89  << PYRAMID_JPEG_YCBCR_COMPRESSION );
90  }
91 
92  connect( mProfileComboBox, static_cast<void ( QComboBox::* )( const QString & )>( &QComboBox::currentIndexChanged ),
93  this, &QgsRasterFormatSaveOptionsWidget::updateOptions );
94  connect( mOptionsTable, &QTableWidget::cellChanged, this, &QgsRasterFormatSaveOptionsWidget::optionsTableChanged );
95  connect( mOptionsHelpButton, &QAbstractButton::clicked, this, &QgsRasterFormatSaveOptionsWidget::helpOptions );
96  connect( mOptionsValidateButton, &QAbstractButton::clicked, this, [ = ] { validateOptions(); } );
97 
98  // create eventFilter to map right click to swapOptionsUI()
99  // mOptionsLabel->installEventFilter( this );
100  mOptionsLineEdit->installEventFilter( this );
101  mOptionsStackedWidget->installEventFilter( this );
102 
103  updateControls();
104  updateProfiles();
105 
106  QgsDebugMsg( QStringLiteral( "done" ) );
107 }
108 
109 void QgsRasterFormatSaveOptionsWidget::setFormat( const QString &format )
110 {
111  mFormat = format;
112  updateControls();
113  updateProfiles();
114 }
115 
116 void QgsRasterFormatSaveOptionsWidget::setProvider( const QString &provider )
117 {
118  mProvider = provider;
119  updateControls();
120 }
121 
122 // show/hide widgets - we need this function if widget is used in creator
124 {
125  QList< QWidget * > widgets = this->findChildren<QWidget *>();
126  if ( ( type == Table ) || ( type == LineEdit ) )
127  {
128  // hide all controls, except stacked widget
129  const auto constWidgets = widgets;
130  for ( QWidget *widget : constWidgets )
131  widget->setVisible( false );
132  mOptionsStackedWidget->setVisible( true );
133  const auto children { mOptionsStackedWidget->findChildren<QWidget *>() };
134  for ( QWidget *widget : children )
135  widget->setVisible( true );
136 
137  // show relevant page
138  if ( type == Table )
139  swapOptionsUI( 0 );
140  else if ( type == LineEdit )
141  swapOptionsUI( 1 );
142  }
143  else
144  {
145  // show all widgets, except profile buttons (unless Full)
146  const auto constWidgets = widgets;
147  for ( QWidget *widget : constWidgets )
148  widget->setVisible( true );
149  if ( type != Full )
150  mProfileButtons->setVisible( false );
151 
152  // show elevant page
153  if ( type == ProfileLineEdit )
154  swapOptionsUI( 1 );
155  }
156 }
157 
158 QString QgsRasterFormatSaveOptionsWidget::pseudoFormat() const
159 {
160  return mPyramids ? QStringLiteral( "_pyramids" ) : mFormat;
161 }
162 
164 {
165  // build profiles list = user + builtin(last)
166  QString format = pseudoFormat();
167  QStringList profileKeys = profiles();
168  QMapIterator<QString, QStringList> it( sBuiltinProfiles );
169  while ( it.hasNext() )
170  {
171  it.next();
172  QString profileKey = it.key();
173  if ( ! profileKeys.contains( profileKey ) && !it.value().isEmpty() )
174  {
175  // insert key if is for all formats or this format (GTiff)
176  if ( it.value()[0].isEmpty() || it.value()[0] == format )
177  {
178  profileKeys.insert( 0, profileKey );
179  }
180  }
181  }
182  std::sort( profileKeys.begin(), profileKeys.end() );
183 
184  // populate mOptionsMap and mProfileComboBox
185  mOptionsMap.clear();
186  mProfileComboBox->blockSignals( true );
187  mProfileComboBox->clear();
188  const auto constProfileKeys = profileKeys;
189  for ( const QString &profileKey : constProfileKeys )
190  {
191  QString profileName, profileOptions;
192  profileOptions = createOptions( profileKey );
193  if ( sBuiltinProfiles.contains( profileKey ) )
194  {
195  profileName = sBuiltinProfiles[ profileKey ][ 1 ];
196  if ( profileOptions.isEmpty() )
197  profileOptions = sBuiltinProfiles[ profileKey ][ 2 ];
198  }
199  else
200  {
201  profileName = profileKey;
202  }
203  mOptionsMap[ profileKey ] = profileOptions;
204  mProfileComboBox->addItem( profileName, profileKey );
205  }
206 
207  // update UI
208  mProfileComboBox->blockSignals( false );
209  // mProfileComboBox->setCurrentIndex( 0 );
210  QgsSettings mySettings;
211  mProfileComboBox->setCurrentIndex( mProfileComboBox->findData( mySettings.value(
212  mProvider + "/driverOptions/" + format.toLower() + "/defaultProfile",
213  "z_adefault" ) ) );
214  updateOptions();
215 }
216 
217 void QgsRasterFormatSaveOptionsWidget::updateOptions()
218 {
219  QString myOptions = mOptionsMap.value( currentProfileKey() );
220  QStringList myOptionsList = myOptions.trimmed().split( ' ', QString::SkipEmptyParts );
221 
222  // If the default JPEG compression profile was selected, remove PHOTOMETRIC_OVERVIEW=YCBCR
223  // if the raster is not RGB. Otherwise this is bound to fail afterwards.
224  if ( mRasterLayer && mRasterLayer->bandCount() != 3 &&
225  myOptions == PYRAMID_JPEG_YCBCR_COMPRESSION )
226  {
227  myOptions = PYRAMID_JPEG_COMPRESSION;
228  }
229 
230  if ( mOptionsStackedWidget->currentIndex() == 0 )
231  {
232  mOptionsTable->setRowCount( 0 );
233  for ( int i = 0; i < myOptionsList.count(); i++ )
234  {
235  QStringList key_value = myOptionsList[i].split( '=' );
236  if ( key_value.count() == 2 )
237  {
238  mOptionsTable->insertRow( i );
239  mOptionsTable->setItem( i, 0, new QTableWidgetItem( key_value[0] ) );
240  mOptionsTable->setItem( i, 1, new QTableWidgetItem( key_value[1] ) );
241  }
242  }
243  }
244  else
245  {
246  mOptionsLineEdit->setText( myOptions );
247  mOptionsLineEdit->setCursorPosition( 0 );
248  }
249 
250  emit optionsChanged();
251 }
252 
254 {
255  setCreateOptions();
256 }
257 
258 // typedefs for gdal provider function pointers
259 typedef QString validateCreationOptionsFormat_t( const QStringList &createOptions, QString format );
260 typedef QString helpCreationOptionsFormat_t( QString format );
261 
263 {
264  QString message;
265 
266  if ( mProvider == QLatin1String( "gdal" ) && !mFormat.isEmpty() && ! mPyramids )
267  {
268  // get helpCreationOptionsFormat() function ptr for provider
269  std::unique_ptr< QLibrary > library( QgsProviderRegistry::instance()->createProviderLibrary( mProvider ) );
270  if ( library )
271  {
272  helpCreationOptionsFormat_t *helpCreationOptionsFormat =
273  ( helpCreationOptionsFormat_t * ) cast_to_fptr( library->resolve( "helpCreationOptionsFormat" ) );
274  if ( helpCreationOptionsFormat )
275  {
276  message = helpCreationOptionsFormat( mFormat );
277  }
278  else
279  {
280  message = library->fileName() + " does not have helpCreationOptionsFormat";
281  }
282  }
283  else
284  message = QStringLiteral( "cannot load provider library %1" ).arg( mProvider );
285 
286 
287  if ( message.isEmpty() )
288  message = tr( "Cannot get create options for driver %1" ).arg( mFormat );
289  }
290  else if ( mProvider == QLatin1String( "gdal" ) && mPyramids )
291  {
292  message = tr( "For details on pyramids options please see the following pages" );
293  message += QLatin1String( "\n\nhttp://www.gdal.org/gdaladdo.html\n\nhttp://www.gdal.org/frmt_gtiff.html" );
294  }
295  else
296  message = tr( "No help available" );
297 
298  // show simple non-modal dialog - should we make the basic xml prettier?
299  QgsDialog *dlg = new QgsDialog( this );
300  QTextEdit *textEdit = new QTextEdit( dlg );
301  textEdit->setReadOnly( true );
302  // message = tr( "Create Options:\n\n%1" ).arg( message );
303  textEdit->setText( message );
304  dlg->layout()->addWidget( textEdit );
305  dlg->resize( 600, 400 );
306 #ifdef Q_OS_MAC
307  dlg->exec(); //modal
308 #else
309  dlg->show(); //non modal
310 #endif
311 }
312 
313 QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool reportOK )
314 {
315  QStringList createOptions = options();
316  QString message;
317 
318  QgsDebugMsg( QStringLiteral( "layer: [%1] file: [%2] format: [%3]" ).arg( mRasterLayer ? mRasterLayer->id() : "none", mRasterFileName, mFormat ) );
319  // if no rasterLayer is defined, but we have a raster fileName, then create a temp. rasterLayer to validate options
320  // ideally we should keep it for future access, but this is trickier
321  QgsRasterLayer *rasterLayer = mRasterLayer;
322  bool tmpLayer = false;
323  if ( !( mRasterLayer && rasterLayer->dataProvider() ) && ! mRasterFileName.isNull() )
324  {
325  // temporarily override /Projections/defaultBehavior to avoid dialog prompt
326  // this is taken from qgsbrowserdockwidget.cpp
327  // TODO - integrate this into qgis core
328  QgsSettings settings;
329  QString defaultProjectionOption = settings.value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString();
330  if ( settings.value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString() == QLatin1String( "prompt" ) )
331  {
332  settings.setValue( QStringLiteral( "Projections/defaultBehavior" ), "useProject" );
333  }
334  tmpLayer = true;
335  rasterLayer = new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), QStringLiteral( "gdal" ) );
336  // restore /Projections/defaultBehavior
337  if ( defaultProjectionOption == QLatin1String( "prompt" ) )
338  {
339  settings.setValue( QStringLiteral( "Projections/defaultBehavior" ), defaultProjectionOption );
340  }
341  }
342 
343  if ( mProvider == QLatin1String( "gdal" ) && mPyramids )
344  {
345  if ( rasterLayer && rasterLayer->dataProvider() )
346  {
347  QgsDebugMsg( QStringLiteral( "calling validate pyramids on layer's data provider" ) );
348  message = rasterLayer->dataProvider()->validatePyramidsConfigOptions( mPyramidsFormat, createOptions, mFormat );
349  }
350  else
351  {
352  message = tr( "cannot validate pyramid options" );
353  }
354  }
355  else if ( !createOptions.isEmpty() && mProvider == QLatin1String( "gdal" ) && !mFormat.isEmpty() )
356  {
357  if ( rasterLayer && rasterLayer->dataProvider() )
358  {
359  QgsDebugMsg( QStringLiteral( "calling validate on layer's data provider" ) );
360  message = rasterLayer->dataProvider()->validateCreationOptions( createOptions, mFormat );
361  }
362  else
363  {
364  // get validateCreationOptionsFormat() function ptr for provider
365  std::unique_ptr< QLibrary > library( QgsProviderRegistry::instance()->createProviderLibrary( mProvider ) );
366  if ( library )
367  {
368  validateCreationOptionsFormat_t *validateCreationOptionsFormat =
369  ( validateCreationOptionsFormat_t * ) cast_to_fptr( library->resolve( "validateCreationOptionsFormat" ) );
370  if ( validateCreationOptionsFormat )
371  {
372  message = validateCreationOptionsFormat( createOptions, mFormat );
373  }
374  else
375  {
376  message = library->fileName() + " does not have validateCreationOptionsFormat";
377  }
378  }
379  else
380  message = QStringLiteral( "cannot load provider library %1" ).arg( mProvider );
381  }
382  }
383  else if ( ! createOptions.isEmpty() )
384  {
385  QMessageBox::information( this, QString(), tr( "Cannot validate creation options." ), QMessageBox::Close );
386  if ( tmpLayer )
387  delete rasterLayer;
388  return QString();
389  }
390 
391  if ( gui )
392  {
393  if ( message.isNull() )
394  {
395  if ( reportOK )
396  QMessageBox::information( this, QString(), tr( "Valid" ), QMessageBox::Close );
397  }
398  else
399  {
400  QMessageBox::warning( this, QString(), tr( "Invalid %1:\n\n%2\n\nClick on help button to get valid creation options for this format." ).arg( mPyramids ? tr( "pyramid creation option" ) : tr( "creation option" ), message ), QMessageBox::Close );
401  }
402  }
403 
404  if ( tmpLayer )
405  delete rasterLayer;
406 
407  return message;
408 }
409 
410 void QgsRasterFormatSaveOptionsWidget::optionsTableChanged()
411 {
412  QTableWidgetItem *key, *value;
413  QString options;
414  for ( int i = 0; i < mOptionsTable->rowCount(); i++ )
415  {
416  key = mOptionsTable->item( i, 0 );
417  if ( ! key || key->text().isEmpty() )
418  continue;
419  value = mOptionsTable->item( i, 1 );
420  if ( ! value || value->text().isEmpty() )
421  continue;
422  options += key->text() + '=' + value->text() + ' ';
423  }
424  options = options.trimmed();
425  mOptionsMap[ currentProfileKey()] = options;
426  mOptionsLineEdit->setText( options );
427  mOptionsLineEdit->setCursorPosition( 0 );
428 }
429 
430 void QgsRasterFormatSaveOptionsWidget::mOptionsLineEdit_editingFinished()
431 {
432  mOptionsMap[ currentProfileKey()] = mOptionsLineEdit->text().trimmed();
433 }
434 
435 void QgsRasterFormatSaveOptionsWidget::mProfileNewButton_clicked()
436 {
437  QString profileName = QInputDialog::getText( this, QString(), tr( "Profile name:" ) );
438  if ( ! profileName.isEmpty() )
439  {
440  profileName = profileName.trimmed();
441  mOptionsMap[ profileName ] = QString();
442  mProfileComboBox->addItem( profileName, profileName );
443  mProfileComboBox->setCurrentIndex( mProfileComboBox->count() - 1 );
444  }
445 }
446 
447 void QgsRasterFormatSaveOptionsWidget::mProfileDeleteButton_clicked()
448 {
449  int index = mProfileComboBox->currentIndex();
450  QString profileKey = currentProfileKey();
451  if ( index != -1 && ! sBuiltinProfiles.contains( profileKey ) )
452  {
453  mOptionsMap.remove( profileKey );
454  mProfileComboBox->removeItem( index );
455  }
456 }
457 
458 void QgsRasterFormatSaveOptionsWidget::mProfileResetButton_clicked()
459 {
460  QString profileKey = currentProfileKey();
461  if ( sBuiltinProfiles.contains( profileKey ) )
462  {
463  mOptionsMap[ profileKey ] = sBuiltinProfiles[ profileKey ][ 2 ];
464  }
465  else
466  {
467  mOptionsMap[ profileKey ] = QString();
468  }
469  mOptionsLineEdit->setText( mOptionsMap.value( currentProfileKey() ) );
470  mOptionsLineEdit->setCursorPosition( 0 );
471  updateOptions();
472 }
473 
474 void QgsRasterFormatSaveOptionsWidget::optionsTableEnableDeleteButton()
475 {
476  mOptionsDeleteButton->setEnabled( mOptionsTable->currentRow() >= 0 );
477 }
478 
479 void QgsRasterFormatSaveOptionsWidget::mOptionsAddButton_clicked()
480 {
481  mOptionsTable->insertRow( mOptionsTable->rowCount() );
482  // select the added row
483  int newRow = mOptionsTable->rowCount() - 1;
484  QTableWidgetItem *item = new QTableWidgetItem();
485  mOptionsTable->setItem( newRow, 0, item );
486  mOptionsTable->setCurrentItem( item );
487 }
488 
489 void QgsRasterFormatSaveOptionsWidget::mOptionsDeleteButton_clicked()
490 {
491  if ( mOptionsTable->currentRow() >= 0 )
492  {
493  mOptionsTable->removeRow( mOptionsTable->currentRow() );
494  // select the previous row or the next one if there is no previous row
495  QTableWidgetItem *item = mOptionsTable->item( mOptionsTable->currentRow(), 0 );
496  mOptionsTable->setCurrentItem( item );
497  optionsTableChanged();
498  }
499 }
500 
501 QString QgsRasterFormatSaveOptionsWidget::settingsKey( QString profileName ) const
502 {
503  if ( !profileName.isEmpty() )
504  profileName = "/profile_" + profileName;
505  else
506  profileName = "/profile_default" + profileName;
507  return mProvider + "/driverOptions/" + pseudoFormat().toLower() + profileName + "/create";
508 }
509 
510 QString QgsRasterFormatSaveOptionsWidget::currentProfileKey() const
511 {
512  return mProfileComboBox->currentData().toString();
513 }
514 
516 {
517  return mOptionsMap.value( currentProfileKey() ).trimmed().split( ' ', QString::SkipEmptyParts );
518 }
519 
520 QString QgsRasterFormatSaveOptionsWidget::createOptions( const QString &profileName ) const
521 {
522  QgsSettings mySettings;
523  return mySettings.value( settingsKey( profileName ), "" ).toString();
524 }
525 
526 void QgsRasterFormatSaveOptionsWidget::deleteCreateOptions( const QString &profileName )
527 {
528  QgsSettings mySettings;
529  mySettings.remove( settingsKey( profileName ) );
530 }
531 
532 void QgsRasterFormatSaveOptionsWidget::setCreateOptions()
533 {
534  QgsSettings mySettings;
535  QStringList myProfiles;
536  QMap< QString, QString >::const_iterator i = mOptionsMap.constBegin();
537  while ( i != mOptionsMap.constEnd() )
538  {
539  setCreateOptions( i.key(), i.value() );
540  myProfiles << i.key();
541  ++i;
542  }
543  mySettings.setValue( mProvider + "/driverOptions/" + pseudoFormat().toLower() + "/profiles",
544  myProfiles );
545  mySettings.setValue( mProvider + "/driverOptions/" + pseudoFormat().toLower() + "/defaultProfile",
546  currentProfileKey().trimmed() );
547 }
548 
549 void QgsRasterFormatSaveOptionsWidget::setCreateOptions( const QString &profileName, const QString &options )
550 {
551  QgsSettings mySettings;
552  mySettings.setValue( settingsKey( profileName ), options.trimmed() );
553 }
554 
555 void QgsRasterFormatSaveOptionsWidget::setCreateOptions( const QString &profileName, const QStringList &list )
556 {
557  setCreateOptions( profileName, list.join( QStringLiteral( " " ) ) );
558 }
559 
560 QStringList QgsRasterFormatSaveOptionsWidget::profiles() const
561 {
562  QgsSettings mySettings;
563  return mySettings.value( mProvider + "/driverOptions/" + pseudoFormat().toLower() + "/profiles", "" ).toStringList();
564 }
565 
566 void QgsRasterFormatSaveOptionsWidget::swapOptionsUI( int newIndex )
567 {
568  // set new page
569  int oldIndex;
570  if ( newIndex == -1 )
571  {
572  oldIndex = mOptionsStackedWidget->currentIndex();
573  newIndex = ( oldIndex + 1 ) % 2;
574  }
575  else
576  {
577  oldIndex = ( newIndex + 1 ) % 2;
578  }
579 
580  // resize pages to minimum - this works well with gdaltools merge ui, but not raster save as...
581  mOptionsStackedWidget->setCurrentIndex( newIndex );
582  mOptionsStackedWidget->widget( newIndex )->setSizePolicy(
583  QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
584  mOptionsStackedWidget->widget( oldIndex )->setSizePolicy(
585  QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) );
586  layout()->activate();
587 
588  updateOptions();
589 }
590 
591 void QgsRasterFormatSaveOptionsWidget::updateControls()
592 {
593  bool valid = mProvider == QLatin1String( "gdal" ) && !mFormat.isEmpty();
594  mOptionsValidateButton->setEnabled( valid );
595  mOptionsHelpButton->setEnabled( valid );
596 }
597 
598 // map options label left mouse click to optionsToggle()
599 bool QgsRasterFormatSaveOptionsWidget::eventFilter( QObject *obj, QEvent *event )
600 {
601  if ( event->type() == QEvent::MouseButtonPress )
602  {
603  QMouseEvent *mouseEvent = static_cast<QMouseEvent *>( event );
604  if ( mouseEvent && ( mouseEvent->button() == Qt::RightButton ) )
605  {
606  QMenu *menu = nullptr;
607  QString text;
608  if ( mOptionsStackedWidget->currentIndex() == 0 )
609  text = tr( "Use simple interface" );
610  else
611  text = tr( "Use table interface" );
612  if ( obj->objectName() == QLatin1String( "mOptionsLineEdit" ) )
613  {
614  menu = mOptionsLineEdit->createStandardContextMenu();
615  menu->addSeparator();
616  }
617  else
618  menu = new QMenu( this );
619  QAction *action = new QAction( text, menu );
620  menu->addAction( action );
621  connect( action, &QAction::triggered, this, &QgsRasterFormatSaveOptionsWidget::swapOptionsUI );
622  menu->exec( mouseEvent->globalPos() );
623  delete menu;
624  return true;
625  }
626  }
627  // standard event processing
628  return QObject::eventFilter( obj, event );
629 }
630 
632 {
633  Q_UNUSED( event )
634  mOptionsTable->horizontalHeader()->resizeSection( 0, mOptionsTable->width() - 115 );
635  QgsDebugMsg( QStringLiteral( "done" ) );
636 }
637 
638 void QgsRasterFormatSaveOptionsWidget::setOptions( const QString &options )
639 {
640  mOptionsTable->blockSignals( true );
641  mOptionsTable->clearContents();
642 
643  QStringList values;
644  QStringList optionsList = options.trimmed().split( ' ', QString::SkipEmptyParts );
645  const auto constOptionsList = optionsList;
646  for ( const QString &opt : constOptionsList )
647  {
648  int rowCount = mOptionsTable->rowCount();
649  mOptionsTable->insertRow( rowCount );
650 
651  values = opt.split( '=' );
652  if ( values.count() == 2 )
653  {
654  QTableWidgetItem *nameItem = new QTableWidgetItem( values.at( 0 ) );
655  mOptionsTable->setItem( rowCount, 0, nameItem );
656  QTableWidgetItem *valueItem = new QTableWidgetItem( values.at( 1 ) );
657  mOptionsTable->setItem( rowCount, 0, valueItem );
658  }
659  }
660 
661  mOptionsMap[ currentProfileKey()] = options.trimmed();
662  mOptionsLineEdit->setText( options.trimmed() );
663  mOptionsLineEdit->setCursorPosition( 0 );
664 
665  mOptionsTable->blockSignals( false );
666 }
int bandCount() const
Returns the number of bands in this layer.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:58
QString helpCreationOptionsFormat_t(QString format)
void setProvider(const QString &provider)
Set provider key, , it is used to determine list of available options.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
void helpOptions()
Opens window with options description for given provider and output format.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
A generic dialog with layout and button box.
Definition: qgsdialog.h:33
virtual QString validatePyramidsConfigOptions(QgsRaster::RasterPyramidsFormat pyramidsFormat, const QStringList &configOptions, const QString &fileFormat)
Validates pyramid creation options for a specific dataset and destination format. ...
void updateProfiles()
Reloads profiles list from QGIS settings.
QString validateCreationOptionsFormat_t(const QStringList &createOptions, QString format)
QgsRasterDataProvider * dataProvider() override
Returns the layer&#39;s data provider, it may be nullptr.
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
void setOptions(const QString &options)
Populate widget with user-defined options.
QString validateOptions(bool gui=true, bool reportOk=true)
Validates options correctness.
QgsRasterFormatSaveOptionsWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, const QString &format="GTiff", QgsRasterFormatSaveOptionsWidget::Type type=Default, const QString &provider="gdal")
#define cast_to_fptr(f)
Definition: qgis.h:158
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
Definition: qgsdialog.h:46
void setType(QgsRasterFormatSaveOptionsWidget::Type type=Default)
Set widget look and feel.
virtual QString validateCreationOptions(const QStringList &createOptions, const QString &format)
Validates creation options for a specific dataset and destination format.
void setFormat(const QString &format)
Set output raster format, it is used to determine list of available options.
QStringList options() const
Returns list of selected options.