24 #include "qgssettings.h"
27 #include <QInputDialog>
28 #include <QMessageBox>
30 #include <QMouseEvent>
34 QMap< QString, QStringList > QgsRasterFormatSaveOptionsWidget::sBuiltinProfiles;
36 static const QString PYRAMID_JPEG_YCBCR_COMPRESSION( QStringLiteral(
"JPEG_QUALITY_OVERVIEW=75 COMPRESS_OVERVIEW=JPEG PHOTOMETRIC_OVERVIEW=YCBCR INTERLEAVE_OVERVIEW=PIXEL" ) );
37 static const QString PYRAMID_JPEG_COMPRESSION( QStringLiteral(
"JPEG_QUALITY_OVERVIEW=75 COMPRESS_OVERVIEW=JPEG INTERLEAVE_OVERVIEW=PIXEL" ) );
43 , mProvider( provider )
46 connect( mProfileNewButton, &QPushButton::clicked,
this, &QgsRasterFormatSaveOptionsWidget::mProfileNewButton_clicked );
47 connect( mProfileDeleteButton, &QPushButton::clicked,
this, &QgsRasterFormatSaveOptionsWidget::mProfileDeleteButton_clicked );
48 connect( mProfileResetButton, &QPushButton::clicked,
this, &QgsRasterFormatSaveOptionsWidget::mProfileResetButton_clicked );
49 connect( mOptionsAddButton, &QPushButton::clicked,
this, &QgsRasterFormatSaveOptionsWidget::mOptionsAddButton_clicked );
50 connect( mOptionsDeleteButton, &QPushButton::clicked,
this, &QgsRasterFormatSaveOptionsWidget::mOptionsDeleteButton_clicked );
51 connect( mOptionsLineEdit, &QLineEdit::editingFinished,
this, &QgsRasterFormatSaveOptionsWidget::mOptionsLineEdit_editingFinished );
55 if ( sBuiltinProfiles.isEmpty() )
58 sBuiltinProfiles[ QStringLiteral(
"z_adefault" )] = ( QStringList() << QString() << tr(
"Default" ) << QString() );
63 sBuiltinProfiles[ QStringLiteral(
"z_gtiff_1big" )] =
64 ( QStringList() << QStringLiteral(
"GTiff" ) << tr(
"No Compression" )
65 << QStringLiteral(
"COMPRESS=NONE BIGTIFF=IF_NEEDED" ) );
66 sBuiltinProfiles[ QStringLiteral(
"z_gtiff_2medium" )] =
67 ( QStringList() << QStringLiteral(
"GTiff" ) << tr(
"Low Compression" )
68 << QStringLiteral(
"COMPRESS=PACKBITS" ) );
69 sBuiltinProfiles[ QStringLiteral(
"z_gtiff_3small" )] =
70 ( QStringList() << QStringLiteral(
"GTiff" ) << tr(
"High Compression" )
71 << QStringLiteral(
"COMPRESS=DEFLATE PREDICTOR=2 ZLEVEL=9" ) );
72 sBuiltinProfiles[ QStringLiteral(
"z_gtiff_4jpeg" )] =
73 ( QStringList() << QStringLiteral(
"GTiff" ) << tr(
"JPEG Compression" )
74 << QStringLiteral(
"COMPRESS=JPEG JPEG_QUALITY=75" ) );
79 sBuiltinProfiles[ QStringLiteral(
"z__pyramids_gtiff_1big" )] =
80 ( QStringList() << QStringLiteral(
"_pyramids" ) << tr(
"No Compression" )
81 << QStringLiteral(
"COMPRESS_OVERVIEW=NONE BIGTIFF_OVERVIEW=IF_NEEDED" ) );
82 sBuiltinProfiles[ QStringLiteral(
"z__pyramids_gtiff_2medium" )] =
83 ( QStringList() << QStringLiteral(
"_pyramids" ) << tr(
"Low Compression" )
84 << QStringLiteral(
"COMPRESS_OVERVIEW=PACKBITS" ) );
85 sBuiltinProfiles[ QStringLiteral(
"z__pyramids_gtiff_3small" )] =
86 ( QStringList() << QStringLiteral(
"_pyramids" ) << tr(
"High Compression" )
87 << QStringLiteral(
"COMPRESS_OVERVIEW=DEFLATE PREDICTOR_OVERVIEW=2 ZLEVEL=9" ) );
88 sBuiltinProfiles[ QStringLiteral(
"z__pyramids_gtiff_4jpeg" )] =
89 ( QStringList() << QStringLiteral(
"_pyramids" ) << tr(
"JPEG Compression" )
90 << PYRAMID_JPEG_YCBCR_COMPRESSION );
93 connect( mProfileComboBox, &QComboBox::currentTextChanged,
94 this, &QgsRasterFormatSaveOptionsWidget::updateOptions );
95 connect( mOptionsTable, &QTableWidget::cellChanged,
this, &QgsRasterFormatSaveOptionsWidget::optionsTableChanged );
97 connect( mOptionsValidateButton, &QAbstractButton::clicked,
this, [ = ] {
validateOptions(); } );
101 mOptionsLineEdit->installEventFilter(
this );
102 mOptionsStackedWidget->installEventFilter(
this );
119 mProvider = provider;
126 QList< QWidget * > widgets = this->findChildren<QWidget *>();
130 const auto constWidgets = widgets;
131 for ( QWidget *widget : constWidgets )
132 widget->setVisible(
false );
133 mOptionsStackedWidget->setVisible(
true );
134 const auto children { mOptionsStackedWidget->findChildren<QWidget *>() };
135 for ( QWidget *widget : children )
136 widget->setVisible(
true );
147 const auto constWidgets = widgets;
148 for ( QWidget *widget : constWidgets )
149 widget->setVisible(
true );
151 mProfileButtons->setVisible(
false );
159 QString QgsRasterFormatSaveOptionsWidget::pseudoFormat()
const
161 return mPyramids ? QStringLiteral(
"_pyramids" ) : mFormat;
167 QString format = pseudoFormat();
168 QStringList profileKeys = profiles();
169 QMapIterator<QString, QStringList> it( sBuiltinProfiles );
170 while ( it.hasNext() )
173 QString profileKey = it.key();
174 if ( ! profileKeys.contains( profileKey ) && !it.value().isEmpty() )
177 if ( it.value()[0].isEmpty() || it.value()[0] == format )
179 profileKeys.insert( 0, profileKey );
183 std::sort( profileKeys.begin(), profileKeys.end() );
187 mProfileComboBox->blockSignals(
true );
188 mProfileComboBox->clear();
189 const auto constProfileKeys = profileKeys;
190 for (
const QString &profileKey : constProfileKeys )
192 QString profileName, profileOptions;
193 profileOptions = createOptions( profileKey );
194 if ( sBuiltinProfiles.contains( profileKey ) )
196 profileName = sBuiltinProfiles[ profileKey ][ 1 ];
197 if ( profileOptions.isEmpty() )
198 profileOptions = sBuiltinProfiles[ profileKey ][ 2 ];
202 profileName = profileKey;
204 mOptionsMap[ profileKey ] = profileOptions;
205 mProfileComboBox->addItem( profileName, profileKey );
209 mProfileComboBox->blockSignals(
false );
211 QgsSettings mySettings;
212 mProfileComboBox->setCurrentIndex( mProfileComboBox->findData( mySettings.value(
213 mProvider +
"/driverOptions/" + format.toLower() +
"/defaultProfile",
218 void QgsRasterFormatSaveOptionsWidget::updateOptions()
220 mBlockOptionUpdates++;
221 QString myOptions = mOptionsMap.value( currentProfileKey() );
222 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
223 QStringList myOptionsList = myOptions.trimmed().split(
' ', QString::SkipEmptyParts );
225 QStringList myOptionsList = myOptions.trimmed().split(
' ', Qt::SkipEmptyParts );
230 if ( mRasterLayer && mRasterLayer->
bandCount() != 3 &&
231 myOptions == PYRAMID_JPEG_YCBCR_COMPRESSION )
233 myOptions = PYRAMID_JPEG_COMPRESSION;
236 if ( mOptionsStackedWidget->currentIndex() == 0 )
238 mOptionsTable->setRowCount( 0 );
239 for (
int i = 0; i < myOptionsList.count(); i++ )
241 QStringList key_value = myOptionsList[i].split(
'=' );
242 if ( key_value.count() == 2 )
244 mOptionsTable->insertRow( i );
245 mOptionsTable->setItem( i, 0,
new QTableWidgetItem( key_value[0] ) );
246 mOptionsTable->setItem( i, 1,
new QTableWidgetItem( key_value[1] ) );
252 mOptionsLineEdit->setText( myOptions );
253 mOptionsLineEdit->setCursorPosition( 0 );
256 mBlockOptionUpdates--;
269 if ( mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty() && ! mPyramids )
272 if ( message.isEmpty() )
273 message = tr(
"Cannot get create options for driver %1" ).arg( mFormat );
275 else if ( mProvider == QLatin1String(
"gdal" ) && mPyramids )
277 message = tr(
"For details on pyramids options please see the following pages" );
278 message += QLatin1String(
"\n\nhttps://gdal.org/programs/gdaladdo.html\n\nhttps://gdal.org/drivers/raster/gtiff.html" );
281 message = tr(
"No help available" );
285 dlg->setWindowTitle( tr(
"Create Options for %1" ).arg( mFormat ) );
286 QTextEdit *textEdit =
new QTextEdit( dlg );
287 textEdit->setReadOnly(
true );
289 textEdit->setText( message );
290 dlg->
layout()->addWidget( textEdit );
291 dlg->resize( 600, 400 );
301 QStringList createOptions =
options();
304 QgsDebugMsg( QStringLiteral(
"layer: [%1] file: [%2] format: [%3]" ).arg( mRasterLayer ? mRasterLayer->
id() :
"none", mRasterFileName, mFormat ) );
308 bool tmpLayer =
false;
309 if ( !( mRasterLayer && rasterLayer->
dataProvider() ) && ! mRasterFileName.isNull() )
313 options.skipCrsValidation =
true;
314 rasterLayer =
new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), QStringLiteral(
"gdal" ),
options );
317 if ( mProvider == QLatin1String(
"gdal" ) && mPyramids )
321 QgsDebugMsg( QStringLiteral(
"calling validate pyramids on layer's data provider" ) );
326 message = tr(
"cannot validate pyramid options" );
329 else if ( !createOptions.isEmpty() && mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty() )
333 QgsDebugMsg( QStringLiteral(
"calling validate on layer's data provider" ) );
343 else if ( ! createOptions.isEmpty() )
345 QMessageBox::information(
this, QString(), tr(
"Cannot validate creation options." ), QMessageBox::Close );
353 if ( message.isNull() )
356 QMessageBox::information(
this, QString(), tr(
"Valid" ), QMessageBox::Close );
360 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 );
370 void QgsRasterFormatSaveOptionsWidget::optionsTableChanged()
372 if ( mBlockOptionUpdates )
375 QTableWidgetItem *key, *value;
377 for (
int i = 0; i < mOptionsTable->rowCount(); i++ )
379 key = mOptionsTable->item( i, 0 );
380 if ( ! key || key->text().isEmpty() )
382 value = mOptionsTable->item( i, 1 );
383 if ( ! value || value->text().isEmpty() )
385 options += key->text() +
'=' + value->text() +
' ';
388 mOptionsMap[ currentProfileKey()] =
options;
389 mOptionsLineEdit->setText(
options );
390 mOptionsLineEdit->setCursorPosition( 0 );
393 void QgsRasterFormatSaveOptionsWidget::mOptionsLineEdit_editingFinished()
395 mOptionsMap[ currentProfileKey()] = mOptionsLineEdit->text().trimmed();
398 void QgsRasterFormatSaveOptionsWidget::mProfileNewButton_clicked()
400 QString profileName = QInputDialog::getText(
this, QString(), tr(
"Profile name:" ) );
401 if ( ! profileName.isEmpty() )
403 profileName = profileName.trimmed();
404 mOptionsMap[ profileName ] = QString();
405 mProfileComboBox->addItem( profileName, profileName );
406 mProfileComboBox->setCurrentIndex( mProfileComboBox->count() - 1 );
410 void QgsRasterFormatSaveOptionsWidget::mProfileDeleteButton_clicked()
412 int index = mProfileComboBox->currentIndex();
413 QString profileKey = currentProfileKey();
414 if ( index != -1 && ! sBuiltinProfiles.contains( profileKey ) )
416 mOptionsMap.remove( profileKey );
417 mProfileComboBox->removeItem( index );
421 void QgsRasterFormatSaveOptionsWidget::mProfileResetButton_clicked()
423 QString profileKey = currentProfileKey();
424 if ( sBuiltinProfiles.contains( profileKey ) )
426 mOptionsMap[ profileKey ] = sBuiltinProfiles[ profileKey ][ 2 ];
430 mOptionsMap[ profileKey ] = QString();
432 mOptionsLineEdit->setText( mOptionsMap.value( currentProfileKey() ) );
433 mOptionsLineEdit->setCursorPosition( 0 );
437 void QgsRasterFormatSaveOptionsWidget::optionsTableEnableDeleteButton()
439 mOptionsDeleteButton->setEnabled( mOptionsTable->currentRow() >= 0 );
442 void QgsRasterFormatSaveOptionsWidget::mOptionsAddButton_clicked()
444 mOptionsTable->insertRow( mOptionsTable->rowCount() );
446 int newRow = mOptionsTable->rowCount() - 1;
447 QTableWidgetItem *item =
new QTableWidgetItem();
448 mOptionsTable->setItem( newRow, 0, item );
449 mOptionsTable->setCurrentItem( item );
452 void QgsRasterFormatSaveOptionsWidget::mOptionsDeleteButton_clicked()
454 if ( mOptionsTable->currentRow() >= 0 )
456 mOptionsTable->removeRow( mOptionsTable->currentRow() );
458 QTableWidgetItem *item = mOptionsTable->item( mOptionsTable->currentRow(), 0 );
459 mOptionsTable->setCurrentItem( item );
460 optionsTableChanged();
464 QString QgsRasterFormatSaveOptionsWidget::settingsKey( QString profileName )
const
466 if ( !profileName.isEmpty() )
467 profileName =
"/profile_" + profileName;
469 profileName =
"/profile_default" + profileName;
470 return mProvider +
"/driverOptions/" + pseudoFormat().toLower() + profileName +
"/create";
473 QString QgsRasterFormatSaveOptionsWidget::currentProfileKey()
const
475 return mProfileComboBox->currentData().toString();
480 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
481 return mOptionsMap.value( currentProfileKey() ).trimmed().split(
' ', QString::SkipEmptyParts );
483 return mOptionsMap.value( currentProfileKey() ).trimmed().split(
' ', Qt::SkipEmptyParts );
487 QString QgsRasterFormatSaveOptionsWidget::createOptions(
const QString &profileName )
const
489 QgsSettings mySettings;
490 return mySettings.value( settingsKey( profileName ),
"" ).toString();
493 void QgsRasterFormatSaveOptionsWidget::deleteCreateOptions(
const QString &profileName )
495 QgsSettings mySettings;
496 mySettings.remove( settingsKey( profileName ) );
499 void QgsRasterFormatSaveOptionsWidget::setCreateOptions()
501 QgsSettings mySettings;
502 QStringList myProfiles;
503 QMap< QString, QString >::const_iterator i = mOptionsMap.constBegin();
504 while ( i != mOptionsMap.constEnd() )
506 setCreateOptions( i.key(), i.value() );
507 myProfiles << i.key();
510 mySettings.setValue( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/profiles",
512 mySettings.setValue( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/defaultProfile",
513 currentProfileKey().trimmed() );
516 void QgsRasterFormatSaveOptionsWidget::setCreateOptions(
const QString &profileName,
const QString &options )
518 QgsSettings mySettings;
519 mySettings.setValue( settingsKey( profileName ),
options.trimmed() );
522 void QgsRasterFormatSaveOptionsWidget::setCreateOptions(
const QString &profileName,
const QStringList &list )
524 setCreateOptions( profileName, list.join( QLatin1Char(
' ' ) ) );
527 QStringList QgsRasterFormatSaveOptionsWidget::profiles()
const
529 QgsSettings mySettings;
530 return mySettings.value( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/profiles",
"" ).toStringList();
533 void QgsRasterFormatSaveOptionsWidget::swapOptionsUI(
int newIndex )
537 if ( newIndex == -1 )
539 oldIndex = mOptionsStackedWidget->currentIndex();
540 newIndex = ( oldIndex + 1 ) % 2;
544 oldIndex = ( newIndex + 1 ) % 2;
548 mOptionsStackedWidget->setCurrentIndex( newIndex );
549 mOptionsStackedWidget->widget( newIndex )->setSizePolicy(
550 QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
551 mOptionsStackedWidget->widget( oldIndex )->setSizePolicy(
552 QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) );
553 layout()->activate();
558 void QgsRasterFormatSaveOptionsWidget::updateControls()
560 bool valid = mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty();
561 mOptionsValidateButton->setEnabled( valid );
562 mOptionsHelpButton->setEnabled( valid );
566 bool QgsRasterFormatSaveOptionsWidget::eventFilter( QObject *obj, QEvent *event )
568 if ( event->type() == QEvent::MouseButtonPress )
570 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
571 if ( mouseEvent && ( mouseEvent->button() == Qt::RightButton ) )
573 QMenu *menu =
nullptr;
575 if ( mOptionsStackedWidget->currentIndex() == 0 )
576 text = tr(
"Use simple interface" );
578 text = tr(
"Use table interface" );
579 if ( obj->objectName() == QLatin1String(
"mOptionsLineEdit" ) )
581 menu = mOptionsLineEdit->createStandardContextMenu();
582 menu->addSeparator();
585 menu =
new QMenu(
this );
586 QAction *action =
new QAction( text, menu );
587 menu->addAction( action );
588 connect( action, &QAction::triggered,
this, &QgsRasterFormatSaveOptionsWidget::swapOptionsUI );
589 menu->exec( mouseEvent->globalPos() );
595 return QObject::eventFilter( obj, event );
601 mOptionsTable->horizontalHeader()->resizeSection( 0, mOptionsTable->width() - 115 );
607 mBlockOptionUpdates++;
608 mOptionsTable->clearContents();
610 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
611 const QStringList optionsList =
options.trimmed().split(
' ', QString::SkipEmptyParts );
613 const QStringList optionsList =
options.trimmed().split(
' ', Qt::SkipEmptyParts );
615 for (
const QString &opt : optionsList )
617 int rowCount = mOptionsTable->rowCount();
618 mOptionsTable->insertRow( rowCount );
620 const QStringList values = opt.split(
'=' );
621 if ( values.count() == 2 )
623 QTableWidgetItem *nameItem =
new QTableWidgetItem( values.at( 0 ) );
624 mOptionsTable->setItem( rowCount, 0, nameItem );
625 QTableWidgetItem *valueItem =
new QTableWidgetItem( values.at( 1 ) );
626 mOptionsTable->setItem( rowCount, 1, valueItem );
632 mProfileComboBox->setCurrentIndex( 0 );
634 mOptionsMap[ currentProfileKey()] =
options.trimmed();
635 mOptionsLineEdit->setText(
options.trimmed() );
636 mOptionsLineEdit->setCursorPosition( 0 );
638 mBlockOptionUpdates--;
A generic dialog with layout and button box.
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
static QString helpCreationOptionsFormat(const QString &format)
Gets creation options metadata for a given format.
static QString validateCreationOptionsFormat(const QStringList &createOptions, const QString &format)
Validates creation options for a given format, regardless of layer.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
virtual QString validateCreationOptions(const QStringList &createOptions, const QString &format)
Validates creation options for a specific dataset and destination format.
virtual QString validatePyramidsConfigOptions(QgsRaster::RasterPyramidsFormat pyramidsFormat, const QStringList &configOptions, const QString &fileFormat)
Validates pyramid creation options for a specific dataset and destination format.
Represents a raster layer.
int bandCount() const
Returns the number of bands in this layer.
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
Setting options for loading raster layers.