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