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 );
212 mProfileComboBox->setCurrentIndex( mProfileComboBox->findData( mySettings.
value(
213 mProvider +
"/driverOptions/" + format.toLower() +
"/defaultProfile",
218 void QgsRasterFormatSaveOptionsWidget::updateOptions()
220 QString myOptions = mOptionsMap.value( currentProfileKey() );
221 QStringList myOptionsList = myOptions.trimmed().split(
' ', QString::SkipEmptyParts );
225 if ( mRasterLayer && mRasterLayer->
bandCount() != 3 &&
226 myOptions == PYRAMID_JPEG_YCBCR_COMPRESSION )
228 myOptions = PYRAMID_JPEG_COMPRESSION;
231 if ( mOptionsStackedWidget->currentIndex() == 0 )
233 mOptionsTable->setRowCount( 0 );
234 for (
int i = 0; i < myOptionsList.count(); i++ )
236 QStringList key_value = myOptionsList[i].split(
'=' );
237 if ( key_value.count() == 2 )
239 mOptionsTable->insertRow( i );
240 mOptionsTable->setItem( i, 0,
new QTableWidgetItem( key_value[0] ) );
241 mOptionsTable->setItem( i, 1,
new QTableWidgetItem( key_value[1] ) );
247 mOptionsLineEdit->setText( myOptions );
248 mOptionsLineEdit->setCursorPosition( 0 );
263 if ( mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty() && ! mPyramids )
266 if ( message.isEmpty() )
267 message = tr(
"Cannot get create options for driver %1" ).arg( mFormat );
269 else if ( mProvider == QLatin1String(
"gdal" ) && mPyramids )
271 message = tr(
"For details on pyramids options please see the following pages" );
272 message += QLatin1String(
"\n\nhttps://gdal.org/programs/gdaladdo.html\n\nhttps://gdal.org/drivers/raster/gtiff.html" );
275 message = tr(
"No help available" );
279 dlg->setWindowTitle( tr(
"Create Options for %1" ).arg( mFormat ) );
280 QTextEdit *textEdit =
new QTextEdit( dlg );
281 textEdit->setReadOnly(
true );
283 textEdit->setText( message );
284 dlg->
layout()->addWidget( textEdit );
285 dlg->resize( 600, 400 );
295 QStringList createOptions =
options();
298 QgsDebugMsg( QStringLiteral(
"layer: [%1] file: [%2] format: [%3]" ).arg( mRasterLayer ? mRasterLayer->
id() :
"none", mRasterFileName, mFormat ) );
302 bool tmpLayer =
false;
303 if ( !( mRasterLayer && rasterLayer->
dataProvider() ) && ! mRasterFileName.isNull() )
308 rasterLayer =
new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), QStringLiteral(
"gdal" ), options );
311 if ( mProvider == QLatin1String(
"gdal" ) && mPyramids )
315 QgsDebugMsg( QStringLiteral(
"calling validate pyramids on layer's data provider" ) );
320 message = tr(
"cannot validate pyramid options" );
323 else if ( !createOptions.isEmpty() && mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty() )
327 QgsDebugMsg( QStringLiteral(
"calling validate on layer's data provider" ) );
337 else if ( ! createOptions.isEmpty() )
339 QMessageBox::information(
this, QString(), tr(
"Cannot validate creation options." ), QMessageBox::Close );
347 if ( message.isNull() )
350 QMessageBox::information(
this, QString(), tr(
"Valid" ), QMessageBox::Close );
354 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 );
364 void QgsRasterFormatSaveOptionsWidget::optionsTableChanged()
366 QTableWidgetItem *key, *value;
368 for (
int i = 0; i < mOptionsTable->rowCount(); i++ )
370 key = mOptionsTable->item( i, 0 );
371 if ( ! key || key->text().isEmpty() )
373 value = mOptionsTable->item( i, 1 );
374 if ( ! value || value->text().isEmpty() )
376 options += key->text() +
'=' + value->text() +
' ';
378 options = options.trimmed();
379 mOptionsMap[ currentProfileKey()] =
options;
380 mOptionsLineEdit->setText( options );
381 mOptionsLineEdit->setCursorPosition( 0 );
384 void QgsRasterFormatSaveOptionsWidget::mOptionsLineEdit_editingFinished()
386 mOptionsMap[ currentProfileKey()] = mOptionsLineEdit->text().trimmed();
389 void QgsRasterFormatSaveOptionsWidget::mProfileNewButton_clicked()
391 QString profileName = QInputDialog::getText(
this, QString(), tr(
"Profile name:" ) );
392 if ( ! profileName.isEmpty() )
394 profileName = profileName.trimmed();
395 mOptionsMap[ profileName ] = QString();
396 mProfileComboBox->addItem( profileName, profileName );
397 mProfileComboBox->setCurrentIndex( mProfileComboBox->count() - 1 );
401 void QgsRasterFormatSaveOptionsWidget::mProfileDeleteButton_clicked()
403 int index = mProfileComboBox->currentIndex();
404 QString profileKey = currentProfileKey();
405 if ( index != -1 && ! sBuiltinProfiles.contains( profileKey ) )
407 mOptionsMap.remove( profileKey );
408 mProfileComboBox->removeItem( index );
412 void QgsRasterFormatSaveOptionsWidget::mProfileResetButton_clicked()
414 QString profileKey = currentProfileKey();
415 if ( sBuiltinProfiles.contains( profileKey ) )
417 mOptionsMap[ profileKey ] = sBuiltinProfiles[ profileKey ][ 2 ];
421 mOptionsMap[ profileKey ] = QString();
423 mOptionsLineEdit->setText( mOptionsMap.value( currentProfileKey() ) );
424 mOptionsLineEdit->setCursorPosition( 0 );
428 void QgsRasterFormatSaveOptionsWidget::optionsTableEnableDeleteButton()
430 mOptionsDeleteButton->setEnabled( mOptionsTable->currentRow() >= 0 );
433 void QgsRasterFormatSaveOptionsWidget::mOptionsAddButton_clicked()
435 mOptionsTable->insertRow( mOptionsTable->rowCount() );
437 int newRow = mOptionsTable->rowCount() - 1;
438 QTableWidgetItem *item =
new QTableWidgetItem();
439 mOptionsTable->setItem( newRow, 0, item );
440 mOptionsTable->setCurrentItem( item );
443 void QgsRasterFormatSaveOptionsWidget::mOptionsDeleteButton_clicked()
445 if ( mOptionsTable->currentRow() >= 0 )
447 mOptionsTable->removeRow( mOptionsTable->currentRow() );
449 QTableWidgetItem *item = mOptionsTable->item( mOptionsTable->currentRow(), 0 );
450 mOptionsTable->setCurrentItem( item );
451 optionsTableChanged();
455 QString QgsRasterFormatSaveOptionsWidget::settingsKey( QString profileName )
const 457 if ( !profileName.isEmpty() )
458 profileName =
"/profile_" + profileName;
460 profileName =
"/profile_default" + profileName;
461 return mProvider +
"/driverOptions/" + pseudoFormat().toLower() + profileName +
"/create";
464 QString QgsRasterFormatSaveOptionsWidget::currentProfileKey()
const 466 return mProfileComboBox->currentData().toString();
471 return mOptionsMap.value( currentProfileKey() ).trimmed().split(
' ', QString::SkipEmptyParts );
474 QString QgsRasterFormatSaveOptionsWidget::createOptions(
const QString &profileName )
const 477 return mySettings.
value( settingsKey( profileName ),
"" ).toString();
480 void QgsRasterFormatSaveOptionsWidget::deleteCreateOptions(
const QString &profileName )
483 mySettings.
remove( settingsKey( profileName ) );
486 void QgsRasterFormatSaveOptionsWidget::setCreateOptions()
489 QStringList myProfiles;
490 QMap< QString, QString >::const_iterator i = mOptionsMap.constBegin();
491 while ( i != mOptionsMap.constEnd() )
493 setCreateOptions( i.key(), i.value() );
494 myProfiles << i.key();
497 mySettings.
setValue( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/profiles",
499 mySettings.
setValue( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/defaultProfile",
500 currentProfileKey().trimmed() );
503 void QgsRasterFormatSaveOptionsWidget::setCreateOptions(
const QString &profileName,
const QString &
options )
506 mySettings.
setValue( settingsKey( profileName ), options.trimmed() );
509 void QgsRasterFormatSaveOptionsWidget::setCreateOptions(
const QString &profileName,
const QStringList &list )
511 setCreateOptions( profileName, list.join( QStringLiteral(
" " ) ) );
514 QStringList QgsRasterFormatSaveOptionsWidget::profiles()
const 517 return mySettings.
value( mProvider +
"/driverOptions/" + pseudoFormat().toLower() +
"/profiles",
"" ).toStringList();
520 void QgsRasterFormatSaveOptionsWidget::swapOptionsUI(
int newIndex )
524 if ( newIndex == -1 )
526 oldIndex = mOptionsStackedWidget->currentIndex();
527 newIndex = ( oldIndex + 1 ) % 2;
531 oldIndex = ( newIndex + 1 ) % 2;
535 mOptionsStackedWidget->setCurrentIndex( newIndex );
536 mOptionsStackedWidget->widget( newIndex )->setSizePolicy(
537 QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) );
538 mOptionsStackedWidget->widget( oldIndex )->setSizePolicy(
539 QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored ) );
540 layout()->activate();
545 void QgsRasterFormatSaveOptionsWidget::updateControls()
547 bool valid = mProvider == QLatin1String(
"gdal" ) && !mFormat.isEmpty();
548 mOptionsValidateButton->setEnabled( valid );
549 mOptionsHelpButton->setEnabled( valid );
553 bool QgsRasterFormatSaveOptionsWidget::eventFilter( QObject *obj, QEvent *event )
555 if ( event->type() == QEvent::MouseButtonPress )
557 QMouseEvent *mouseEvent =
static_cast<QMouseEvent *
>( event );
558 if ( mouseEvent && ( mouseEvent->button() == Qt::RightButton ) )
560 QMenu *menu =
nullptr;
562 if ( mOptionsStackedWidget->currentIndex() == 0 )
563 text = tr(
"Use simple interface" );
565 text = tr(
"Use table interface" );
566 if ( obj->objectName() == QLatin1String(
"mOptionsLineEdit" ) )
568 menu = mOptionsLineEdit->createStandardContextMenu();
569 menu->addSeparator();
572 menu =
new QMenu(
this );
573 QAction *action =
new QAction( text, menu );
574 menu->addAction( action );
575 connect( action, &QAction::triggered,
this, &QgsRasterFormatSaveOptionsWidget::swapOptionsUI );
576 menu->exec( mouseEvent->globalPos() );
582 return QObject::eventFilter( obj, event );
588 mOptionsTable->horizontalHeader()->resizeSection( 0, mOptionsTable->width() - 115 );
594 mOptionsTable->blockSignals(
true );
595 mOptionsTable->clearContents();
598 QStringList optionsList = options.trimmed().split(
' ', QString::SkipEmptyParts );
599 const auto constOptionsList = optionsList;
600 for (
const QString &opt : constOptionsList )
602 int rowCount = mOptionsTable->rowCount();
603 mOptionsTable->insertRow( rowCount );
605 values = opt.split(
'=' );
606 if ( values.count() == 2 )
608 QTableWidgetItem *nameItem =
new QTableWidgetItem( values.at( 0 ) );
609 mOptionsTable->setItem( rowCount, 0, nameItem );
610 QTableWidgetItem *valueItem =
new QTableWidgetItem( values.at( 1 ) );
611 mOptionsTable->setItem( rowCount, 0, valueItem );
615 mOptionsMap[ currentProfileKey()] = options.trimmed();
616 mOptionsLineEdit->setText( options.trimmed() );
617 mOptionsLineEdit->setCursorPosition( 0 );
619 mOptionsTable->blockSignals(
false );
int bandCount() const
Returns the number of bands in this layer.
This class is a composition of two QSettings instances:
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
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.
virtual QString validatePyramidsConfigOptions(QgsRaster::RasterPyramidsFormat pyramidsFormat, const QStringList &configOptions, const QString &fileFormat)
Validates pyramid creation options for a specific dataset and destination format. ...
QgsRasterDataProvider * dataProvider() override
Returns the source data provider.
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
bool skipCrsValidation
Controls whether the layer is allowed to have an invalid/unknown CRS.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QString validateCreationOptionsFormat(const QStringList &createOptions, QString format)
Validates creation options for a given format, regardless of layer.
QVBoxLayout * layout()
Returns the central layout. Widgets added to it must have this dialog as parent.
static QString helpCreationOptionsFormat(QString format)
Gets creation options metadata for a given format.
virtual QString validateCreationOptions(const QStringList &createOptions, const QString &format)
Validates creation options for a specific dataset and destination format.
Setting options for loading raster layers.