Skip to content

Commit c5668f3

Browse files
committed
[FEATURE] Add a menu entry to memory layers to Make Permanent
Prompts for a location to save the layer to, then replaces it in place (keeping the same id, style, etc)
1 parent efd5cc5 commit c5668f3

File tree

3 files changed

+99
-15
lines changed

3 files changed

+99
-15
lines changed

src/app/qgisapp.cpp

Lines changed: 79 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7166,7 +7166,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
71667166
emit layerSavedAs( rlWeakPointer, fileName );
71677167

71687168
messageBar()->pushMessage( tr( "Layer Exported" ),
7169-
tr( "Successfully saved raster layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( newFilename ).toString(), QDir::toNativeSeparators( newFilename ) ),
7169+
tr( "Successfully saved raster layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( QFileInfo( newFilename ).path() ).toString(), QDir::toNativeSeparators( newFilename ) ),
71707170
Qgis::Success, messageTimeout() );
71717171
} );
71727172

@@ -7204,6 +7204,45 @@ void QgisApp::saveAsFile( QgsMapLayer *layer, bool onlySelected )
72047204
}
72057205
}
72067206

7207+
void QgisApp::makeMemoryLayerPermanent( QgsVectorLayer *layer )
7208+
{
7209+
if ( !layer )
7210+
return;
7211+
7212+
const QString layerId = layer->id();
7213+
7214+
auto onSuccess = [this, layerId]( const QString & newFilename,
7215+
bool,
7216+
const QString &,
7217+
const QString &,
7218+
const QString & )
7219+
{
7220+
// we have to re-retrieve the layer, in case it's been removed during the lifetime of the writer task
7221+
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( QgsProject::instance()->mapLayer( layerId ) );
7222+
if ( vl )
7223+
{
7224+
QgsDataProvider::ProviderOptions options;
7225+
vl->setDataSource( QStringLiteral( "%1" ).arg( newFilename ), vl->name(), QStringLiteral( "ogr" ), options );
7226+
this->messageBar()->pushMessage( tr( "Layer Saved" ),
7227+
tr( "Successfully saved scratch layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( QFileInfo( newFilename ).path() ).toString(), QDir::toNativeSeparators( newFilename ) ),
7228+
Qgis::Success, messageTimeout() );
7229+
}
7230+
};
7231+
7232+
auto onFailure = []( int error, const QString & errorMessage )
7233+
{
7234+
if ( error != QgsVectorFileWriter::Canceled )
7235+
{
7236+
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
7237+
m->setWindowTitle( tr( "Save Error" ) );
7238+
m->setMessageAsPlainText( tr( "Could not make temporary scratch layer permanent.\nError: %1" ).arg( errorMessage ) );
7239+
m->exec();
7240+
}
7241+
};
7242+
7243+
saveAsVectorFileGeneral( layer, true, false, onSuccess, onFailure );
7244+
}
7245+
72077246
void QgisApp::saveAsLayerDefinition()
72087247
{
72097248
QString path = QFileDialog::getSaveFileName( this, QStringLiteral( "Save as Layer Definition File" ), QDir::home().path(), QStringLiteral( "*.qlr" ) );
@@ -7310,6 +7349,42 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
73107349
if ( !vlayer )
73117350
return;
73127351

7352+
auto onSuccess = [this, vlayer]( const QString & newFilename,
7353+
bool addToCanvas,
7354+
const QString & layerName,
7355+
const QString & encoding,
7356+
const QString & vectorFileName )
7357+
{
7358+
if ( addToCanvas )
7359+
{
7360+
QString uri( newFilename );
7361+
if ( !layerName.isEmpty() )
7362+
uri += "|layername=" + layerName;
7363+
this->addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
7364+
}
7365+
7366+
this->emit layerSavedAs( vlayer, vectorFilename );
7367+
this->messageBar()->pushMessage( tr( "Layer Exported" ),
7368+
tr( "Successfully saved vector layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( newFilename ).toString(), QDir::toNativeSeparators( newFilename ) ),
7369+
Qgis::Success, messageTimeout() );
7370+
};
7371+
7372+
auto onFailure = []( int error, const QString & errorMessage )
7373+
{
7374+
if ( error != QgsVectorFileWriter::Canceled )
7375+
{
7376+
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
7377+
m->setWindowTitle( tr( "Save Error" ) );
7378+
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
7379+
m->exec();
7380+
}
7381+
};
7382+
7383+
saveAsVectorFileGeneral( vlayer, symbologyOption, onlySelected, onSuccess, onFailure );
7384+
}
7385+
7386+
void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected, const std::function<void( const QString &, bool, const QString &, const QString &, const QString & )> &onSuccess, const std::function<void ( int, const QString & )> &onFailure )
7387+
{
73137388
QgsCoordinateReferenceSystem destCRS;
73147389

73157390
int options = QgsVectorLayerSaveAsDialog::AllOptions;
@@ -7381,21 +7456,10 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
73817456
QgsVectorFileWriterTask *writerTask = new QgsVectorFileWriterTask( vlayer, vectorFilename, options );
73827457

73837458
// when writer is successful:
7384-
connect( writerTask, &QgsVectorFileWriterTask::writeComplete, this, [this, addToCanvas, layerName, encoding, vectorFilename, vlayer]( const QString & newFilename )
7459+
connect( writerTask, &QgsVectorFileWriterTask::writeComplete, this, [onSuccess, addToCanvas, layerName, encoding, vectorFilename]( const QString & newFilename )
73857460
{
7386-
if ( addToCanvas )
7387-
{
7388-
QString uri( newFilename );
7389-
if ( !layerName.isEmpty() )
7390-
uri += "|layername=" + layerName;
7391-
this->addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
7392-
}
7393-
this->emit layerSavedAs( vlayer, vectorFilename );
7394-
this->messageBar()->pushMessage( tr( "Layer Exported" ),
7395-
tr( "Successfully saved vector layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( newFilename ).toString(), QDir::toNativeSeparators( newFilename ) ),
7396-
Qgis::Success, messageTimeout() );
7397-
}
7398-
);
7461+
onSuccess( newFilename, addToCanvas, layerName, encoding, vectorFilename );
7462+
} );
73997463

74007464
// when an error occurs:
74017465
connect( writerTask, &QgsVectorFileWriterTask::errorOccurred, this, [ = ]( int error, const QString & errorMessage )

src/app/qgisapp.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
695695
public slots:
696696
//! save current vector layer
697697
void saveAsFile( QgsMapLayer *layer = nullptr, bool onlySelected = false );
698+
699+
/**
700+
* Makes a memory layer permanent, by prompting users to save the layer to a disk-based (OGR)
701+
* format, and then replacing the layer's data source in place.
702+
*/
703+
void makeMemoryLayerPermanent( QgsVectorLayer *layer );
704+
698705
//! save qml style for the current layer
699706
void saveStyleFile( QgsMapLayer *layer = nullptr );
700707
//! save qrl definition for the current layer
@@ -1829,6 +1836,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
18291836

18301837
void saveAsVectorFileGeneral( QgsVectorLayer *vlayer = nullptr, bool symbologyOption = true, bool onlySelected = false );
18311838

1839+
void saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected,
1840+
const std::function< void ( const QString &newFilename,
1841+
bool addToCanvas,
1842+
const QString &layerName,
1843+
const QString &encoding,
1844+
const QString &vectorFileName )> &onSuccess, const std::function< void ( int error, const QString &errorMessage ) > &onFailure );
1845+
18321846
//! Sets project properties, including map untis
18331847
void projectProperties( const QString &currentPage = QString() );
18341848

src/app/qgsapplayertreeviewmenuprovider.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,12 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()
261261

262262
if ( vlayer )
263263
{
264+
if ( vlayer->dataProvider()->name() == QLatin1String( "memory" ) )
265+
{
266+
QAction *actionMakePermenant = new QAction( QgsApplication::getThemeIcon( QStringLiteral( "mActionFileSave.svg" ) ), tr( "Make Permanent…" ), menu );
267+
connect( actionMakePermenant, &QAction::triggered, QgisApp::instance(), [ = ] { QgisApp::instance()->makeMemoryLayerPermanent( vlayer ); } );
268+
menu->addAction( actionMakePermenant );
269+
}
264270
// save as vector file
265271
QMenu *menuExportVector = new QMenu( tr( "Export" ), menu );
266272
QAction *actionSaveAs = new QAction( tr( "Save Features As…" ), menuExportVector );

0 commit comments

Comments
 (0)