Skip to content
Permalink
Browse files

[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)
  • Loading branch information
nyalldawson committed Aug 3, 2018
1 parent efd5cc5 commit c5668f371d5d5a838b2def14254da2a6758a20b5
Showing with 99 additions and 15 deletions.
  1. +79 −15 src/app/qgisapp.cpp
  2. +14 −0 src/app/qgisapp.h
  3. +6 −0 src/app/qgsapplayertreeviewmenuprovider.cpp
@@ -7166,7 +7166,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
emit layerSavedAs( rlWeakPointer, fileName );

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

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

void QgisApp::makeMemoryLayerPermanent( QgsVectorLayer *layer )
{
if ( !layer )
return;

const QString layerId = layer->id();

auto onSuccess = [this, layerId]( const QString & newFilename,
bool,
const QString &,
const QString &,
const QString & )
{
// we have to re-retrieve the layer, in case it's been removed during the lifetime of the writer task
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer * >( QgsProject::instance()->mapLayer( layerId ) );
if ( vl )
{
QgsDataProvider::ProviderOptions options;
vl->setDataSource( QStringLiteral( "%1" ).arg( newFilename ), vl->name(), QStringLiteral( "ogr" ), options );
this->messageBar()->pushMessage( tr( "Layer Saved" ),
tr( "Successfully saved scratch layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( QFileInfo( newFilename ).path() ).toString(), QDir::toNativeSeparators( newFilename ) ),
Qgis::Success, messageTimeout() );
}
};

auto onFailure = []( int error, const QString & errorMessage )
{
if ( error != QgsVectorFileWriter::Canceled )
{
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
m->setWindowTitle( tr( "Save Error" ) );
m->setMessageAsPlainText( tr( "Could not make temporary scratch layer permanent.\nError: %1" ).arg( errorMessage ) );
m->exec();
}
};

saveAsVectorFileGeneral( layer, true, false, onSuccess, onFailure );
}

void QgisApp::saveAsLayerDefinition()
{
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
if ( !vlayer )
return;

auto onSuccess = [this, vlayer]( const QString & newFilename,
bool addToCanvas,
const QString & layerName,
const QString & encoding,
const QString & vectorFileName )
{
if ( addToCanvas )
{
QString uri( newFilename );
if ( !layerName.isEmpty() )
uri += "|layername=" + layerName;
this->addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
}

this->emit layerSavedAs( vlayer, vectorFilename );
this->messageBar()->pushMessage( tr( "Layer Exported" ),
tr( "Successfully saved vector layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( newFilename ).toString(), QDir::toNativeSeparators( newFilename ) ),
Qgis::Success, messageTimeout() );
};

auto onFailure = []( int error, const QString & errorMessage )
{
if ( error != QgsVectorFileWriter::Canceled )
{
QgsMessageViewer *m = new QgsMessageViewer( nullptr );
m->setWindowTitle( tr( "Save Error" ) );
m->setMessageAsPlainText( tr( "Export to vector file failed.\nError: %1" ).arg( errorMessage ) );
m->exec();
}
};

saveAsVectorFileGeneral( vlayer, symbologyOption, onlySelected, onSuccess, onFailure );
}

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 )
{
QgsCoordinateReferenceSystem destCRS;

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

// when writer is successful:
connect( writerTask, &QgsVectorFileWriterTask::writeComplete, this, [this, addToCanvas, layerName, encoding, vectorFilename, vlayer]( const QString & newFilename )
connect( writerTask, &QgsVectorFileWriterTask::writeComplete, this, [onSuccess, addToCanvas, layerName, encoding, vectorFilename]( const QString & newFilename )
{
if ( addToCanvas )
{
QString uri( newFilename );
if ( !layerName.isEmpty() )
uri += "|layername=" + layerName;
this->addVectorLayers( QStringList( uri ), encoding, QStringLiteral( "file" ) );
}
this->emit layerSavedAs( vlayer, vectorFilename );
this->messageBar()->pushMessage( tr( "Layer Exported" ),
tr( "Successfully saved vector layer to <a href=\"%1\">%2</a>" ).arg( QUrl::fromLocalFile( newFilename ).toString(), QDir::toNativeSeparators( newFilename ) ),
Qgis::Success, messageTimeout() );
}
);
onSuccess( newFilename, addToCanvas, layerName, encoding, vectorFilename );
} );

// when an error occurs:
connect( writerTask, &QgsVectorFileWriterTask::errorOccurred, this, [ = ]( int error, const QString & errorMessage )
@@ -695,6 +695,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
public slots:
//! save current vector layer
void saveAsFile( QgsMapLayer *layer = nullptr, bool onlySelected = false );

/**
* Makes a memory layer permanent, by prompting users to save the layer to a disk-based (OGR)
* format, and then replacing the layer's data source in place.
*/
void makeMemoryLayerPermanent( QgsVectorLayer *layer );

//! save qml style for the current layer
void saveStyleFile( QgsMapLayer *layer = nullptr );
//! save qrl definition for the current layer
@@ -1829,6 +1836,13 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

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

void saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected,
const std::function< void ( const QString &newFilename,
bool addToCanvas,
const QString &layerName,
const QString &encoding,
const QString &vectorFileName )> &onSuccess, const std::function< void ( int error, const QString &errorMessage ) > &onFailure );

//! Sets project properties, including map untis
void projectProperties( const QString &currentPage = QString() );

@@ -261,6 +261,12 @@ QMenu *QgsAppLayerTreeViewMenuProvider::createContextMenu()

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

0 comments on commit c5668f3

Please sign in to comment.
You can’t perform that action at this time.