diff --git a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in index 78d6ee5ef29..8c68677d3ea 100644 --- a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in +++ b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in @@ -54,6 +54,7 @@ Constructor for QgsRasterLayerSaveAsDialog bool tileMode() const; bool addToCanvas() const; QString outputFileName() const; + QString outputLayerName() const; QString outputFormat() const; QgsCoordinateReferenceSystem outputCrs(); QStringList createOptions() const; @@ -72,6 +73,7 @@ Constructor for QgsRasterLayerSaveAsDialog public slots: virtual void accept(); + }; diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index cac5ffef8b0..d40269227ba 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -7156,13 +7156,16 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer ) bool tileMode = d.tileMode(); bool addToCanvas = d.addToCanvas(); QPointer< QgsRasterLayer > rlWeakPointer( rasterLayer ); + QString outputLayerName = d.outputLayerName(); + QString outputFormat = d.outputFormat(); QgsRasterFileWriterTask *writerTask = new QgsRasterFileWriterTask( fileWriter, pipe.release(), d.nColumns(), d.nRows(), d.outputRectangle(), d.outputCrs() ); // when writer is successful: - connect( writerTask, &QgsRasterFileWriterTask::writeComplete, this, [this, tileMode, addToCanvas, rlWeakPointer ]( const QString & newFilename ) + connect( writerTask, &QgsRasterFileWriterTask::writeComplete, this, + [this, tileMode, addToCanvas, rlWeakPointer, outputLayerName, outputFormat]( const QString & newFilename ) { QString fileName = newFilename; if ( tileMode ) @@ -7173,7 +7176,14 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer ) if ( addToCanvas ) { - addRasterLayers( QStringList( fileName ) ); + if ( outputFormat == QLatin1String( "GPKG" ) && !outputLayerName.isEmpty() ) + { + addRasterLayers( QStringList( QStringLiteral( "GPKG:%1:%2" ).arg( fileName, outputLayerName ) ) ); + } + else + { + addRasterLayers( QStringList( fileName ) ); + } } if ( rlWeakPointer ) emit layerSavedAs( rlWeakPointer, fileName ); @@ -12811,7 +12821,17 @@ bool QgisApp::addRasterLayers( QStringList const &fileNameQStringList, bool guiW QFileInfo myFileInfo( *myIterator ); // try to create the layer - QgsRasterLayer *layer = addRasterLayerPrivate( *myIterator, myFileInfo.completeBaseName(), + // set the layer name to the file base name... + QString layerName = myFileInfo.completeBaseName(); + + // ...unless the layer uri matches "GPKG:filePath:layerName" and layerName differs from the file base name + QStringList layerUriSegments = myIterator->split( QLatin1String( ":" ) ); + if ( layerUriSegments.count() == 3 && layerUriSegments[ 0 ] == QLatin1String( "GPKG" ) && layerUriSegments[ 2 ] != layerName ) + { + layerName = QStringLiteral( "%1 %2" ).arg( layerName, layerUriSegments[ 2 ] ); + } + + QgsRasterLayer *layer = addRasterLayerPrivate( *myIterator, layerName, QString(), guiWarning, true ); if ( layer && layer->isValid() ) { diff --git a/src/gui/qgsrasterlayersaveasdialog.cpp b/src/gui/qgsrasterlayersaveasdialog.cpp index 3f6110acf8d..4b4c621b376 100644 --- a/src/gui/qgsrasterlayersaveasdialog.cpp +++ b/src/gui/qgsrasterlayersaveasdialog.cpp @@ -179,6 +179,12 @@ QgsRasterLayerSaveAsDialog::QgsRasterLayerSaveAsDialog( QgsRasterLayer *rasterLa QFileInfo tmplFileInfo( filePath ); settings.setValue( QStringLiteral( "UI/lastRasterFileDir" ), tmplFileInfo.absolutePath() ); + if ( !filePath.isEmpty() && mLayerName->isEnabled() ) + { + QFileInfo fileInfo( filePath ); + mLayerName->setText( fileInfo.baseName() ); + } + if ( mTileModeCheckBox->isChecked() ) { QString fileName = filePath; @@ -314,6 +320,18 @@ void QgsRasterLayerSaveAsDialog::mFormatComboBox_currentIndexChanged( const QStr tr( "All files (*.*)" ) ); } mFilename->setFilter( filter ); + + mFilename->setConfirmOverwrite( outputFormat() != QStringLiteral( "GPKG" ) ); + mLayerName->setEnabled( outputFormat() == QStringLiteral( "GPKG" ) ); + if ( mLayerName->isEnabled() ) + { + QString layerName = QFileInfo( mFilename->filePath() ).baseName(); + mLayerName->setText( layerName ); + } + else + { + mLayerName->setText( QString() ); + } } int QgsRasterLayerSaveAsDialog::nColumns() const @@ -380,6 +398,19 @@ QString QgsRasterLayerSaveAsDialog::outputFileName() const return fileName; } +QString QgsRasterLayerSaveAsDialog::outputLayerName() const +{ + if ( mLayerName->text().isEmpty() && outputFormat() == QStringLiteral( "GPKG" ) && !mTileModeCheckBox->isChecked() ) + { + // Always return layer name for GeoPackages + return QFileInfo( mFilename->filePath() ).baseName(); + } + else + { + return mLayerName->text(); + } +} + QString QgsRasterLayerSaveAsDialog::outputFormat() const { return mFormatComboBox->currentData().toString(); @@ -387,7 +418,35 @@ QString QgsRasterLayerSaveAsDialog::outputFormat() const QStringList QgsRasterLayerSaveAsDialog::createOptions() const { - return mCreateOptionsGroupBox->isChecked() ? mCreateOptionsWidget->options() : QStringList(); + QStringList options = mCreateOptionsGroupBox->isChecked() ? mCreateOptionsWidget->options() : QStringList(); + if ( outputFormat() == QStringLiteral( "GPKG" ) ) + { + // Overwrite the GPKG table options + int indx = options.indexOf( QRegExp( "^RASTER_TABLE=.*" ) ); + if ( indx > -1 ) + { + options.replace( indx, QStringLiteral( "RASTER_TABLE=%1" ).arg( outputLayerName() ) ); + } + else + { + options.append( QStringLiteral( "RASTER_TABLE=%1" ).arg( outputLayerName() ) ); + } + + // Only enable the append mode if the layer doesn't exist yet. For existing layers a 'confirm overwrite' dialog will be shown. + if ( !outputLayerExistsInGpkg() ) + { + indx = options.indexOf( QRegExp( "^APPEND_SUBDATASET=.*", Qt::CaseInsensitive ) ); + if ( indx > -1 ) + { + options.replace ( indx, QStringLiteral( "APPEND_SUBDATASET=YES" ) ); + } + else + { + options.append( QStringLiteral( "APPEND_SUBDATASET=YES" ) ); + } + } + } + return options; } QgsRectangle QgsRasterLayerSaveAsDialog::outputRectangle() const @@ -845,6 +904,32 @@ bool QgsRasterLayerSaveAsDialog::validate() const return true; } +bool QgsRasterLayerSaveAsDialog::outputLayerExistsInGpkg() const +{ + QgsRasterLayer *layer = nullptr; + layer = new QgsRasterLayer( QStringLiteral( "GPKG:%1:%2" ).arg( outputFileName(), outputLayerName() ), "", QStringLiteral( "gdal" ) ); + return layer->isValid(); +} + +void QgsRasterLayerSaveAsDialog::accept() +{ + if ( !validate() ) + { + return; + } + + if ( outputFormat() == QStringLiteral( "GPKG" ) && outputLayerExistsInGpkg() && + QMessageBox::warning( this, tr( "Save Raster Layer" ), + tr( "The layer %1 already exists in the target file, and overwriting layers in GeoPackage is not supported. " + "Do you want to overwrite the whole file?" ).arg( outputLayerName() ), + QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No ) + { + return; + } + + QDialog::accept(); +} + void QgsRasterLayerSaveAsDialog::showHelp() { QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#save-layer-from-an-existing-file" ) ); diff --git a/src/gui/qgsrasterlayersaveasdialog.h b/src/gui/qgsrasterlayersaveasdialog.h index 5b24a0b3127..a828ab35e05 100644 --- a/src/gui/qgsrasterlayersaveasdialog.h +++ b/src/gui/qgsrasterlayersaveasdialog.h @@ -71,6 +71,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast bool tileMode() const; bool addToCanvas() const; QString outputFileName() const; + QString outputLayerName() const; QString outputFormat() const; QgsCoordinateReferenceSystem outputCrs(); QStringList createOptions() const; @@ -87,7 +88,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast void hideOutput(); public slots: - void accept() override { if ( validate() ) QDialog::accept(); } + void accept() override; private slots: void mRawModeRadioButton_toggled( bool ); @@ -138,6 +139,7 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast double noDataCellValue( int row, int column ) const; void adjustNoDataCellWidth( int row, int column ); bool validate() const; + bool outputLayerExistsInGpkg() const; void insertAvailableOutputFormats(); }; diff --git a/src/ui/qgsrasterlayersaveasdialogbase.ui b/src/ui/qgsrasterlayersaveasdialogbase.ui index 2137d439dfc..e92a8bf327c 100644 --- a/src/ui/qgsrasterlayersaveasdialogbase.ui +++ b/src/ui/qgsrasterlayersaveasdialogbase.ui @@ -7,7 +7,7 @@ 0 0 575 - 580 + 610 @@ -86,7 +86,7 @@ - + Qt::StrongFocus @@ -118,7 +118,7 @@ datasets with maximum width and height specified below. - + @@ -147,7 +147,7 @@ datasets with maximum width and height specified below. - + Add saved file to map @@ -157,6 +157,16 @@ datasets with maximum width and height specified below. + + + + Layer name + + + + + + @@ -716,6 +726,7 @@ datasets with maximum width and height specified below. mFormatComboBox mTileModeCheckBox mFilename + mLayerName mCrsSelector mAddToCanvas mScrollArea