Skip to content

Commit

Permalink
[FEATURE] Add "export to file" options for raster and vector layers
Browse files Browse the repository at this point in the history
within the browser panel

Allows direct export of these files (e.g. to a different format,
crs, etc) without having to actually load them into a project
first.
  • Loading branch information
nyalldawson committed Oct 26, 2018
1 parent 2089887 commit 7ac5215
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 29 deletions.
16 changes: 16 additions & 0 deletions python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in
Expand Up @@ -52,7 +52,23 @@ Constructor for QgsRasterLayerSaveAsDialog
int maximumTileSizeX() const;
int maximumTileSizeY() const;
bool tileMode() const;

bool addToCanvas() const;
%Docstring
Returns true if the "add to canvas" checkbox is checked.

.. seealso:: :py:func:`setAddToCanvas`
%End

void setAddToCanvas( bool checked );
%Docstring
Sets whether the "add to canvas" checkbox should be ``checked``.

.. seealso:: :py:func:`addToCanvas`

.. versionadded:: 3.6
%End

QString outputFileName() const;

QString outputLayerName() const;
Expand Down
35 changes: 35 additions & 0 deletions python/gui/auto_generated/qgswindowmanagerinterface.sip.in
Expand Up @@ -9,6 +9,7 @@




class QgsWindowManagerInterface
{
%Docstring
Expand Down Expand Up @@ -44,6 +45,40 @@ existing instance to the foreground.

Returns the dialog if shown, or None if the dialog either could not be
created or is not supported by the window manager implementation.
%End

virtual QString executeExportVectorLayerDialog( QgsVectorLayer *layer );
%Docstring
Executes the standard "Export Vector Layer" dialog for the specified ``layer``,
and performs an export using the settings accepted in the dialog.

The created vector file name is returned.

Depending on the window manager implementation the actual export of the
layer may occur in a background task, in which case calling this method
will immediately return after the dialog has been accepted, but before
the exported layer has been finalized.

.. seealso:: :py:func:`executeExportRasterLayerDialog`

.. versionadded:: 3.6
%End

virtual QString executeExportRasterLayerDialog( QgsRasterLayer *layer );
%Docstring
Executes the standard "Export Raster Layer" dialog for the specified ``layer``,
and performs an export using the settings accepted in the dialog.

The created raster file name is returned.

Depending on the window manager implementation the actual export of the
layer may occur in a background task, in which case calling this method
will immediately return after the dialog has been accepted, but before
the exported layer has been finalized.

.. seealso:: :py:func:`executeExportVectorLayerDialog`

.. versionadded:: 3.6
%End

};
Expand Down
42 changes: 24 additions & 18 deletions src/app/qgisapp.cpp
Expand Up @@ -7160,22 +7160,23 @@ void QgisApp::attributeTable( QgsAttributeTableFilterModel::FilterMode filter )
// the dialog will be deleted by itself on close
}

void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
QString QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer, const bool defaultAddToCanvas )
{
if ( !rasterLayer )
rasterLayer = qobject_cast<QgsRasterLayer *>( activeLayer() );

if ( !rasterLayer )
{
return;
return QString();
}

QgsRasterLayerSaveAsDialog d( rasterLayer, rasterLayer->dataProvider(),
mMapCanvas->extent(), rasterLayer->crs(),
mMapCanvas->mapSettings().destinationCrs(),
this );
d.setAddToCanvas( defaultAddToCanvas );
if ( d.exec() == QDialog::Rejected )
return;
return QString();

QgsSettings settings;
settings.setValue( QStringLiteral( "UI/lastRasterFileDir" ), QFileInfo( d.outputFileName() ).absolutePath() );
Expand Down Expand Up @@ -7205,7 +7206,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
if ( !pipe->set( rasterLayer->dataProvider()->clone() ) )
{
QgsDebugMsg( QStringLiteral( "Cannot set pipe provider" ) );
return;
return QString();
}

QgsRasterNuller *nuller = new QgsRasterNuller();
Expand All @@ -7216,7 +7217,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
if ( !pipe->insert( 1, nuller ) )
{
QgsDebugMsg( QStringLiteral( "Cannot set pipe nuller" ) );
return;
return QString();
}

// add projector if necessary
Expand All @@ -7227,7 +7228,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
if ( !pipe->insert( 2, projector ) )
{
QgsDebugMsg( QStringLiteral( "Cannot set pipe projector" ) );
return;
return QString();
}
}
}
Expand All @@ -7240,14 +7241,14 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
if ( !projector )
{
QgsDebugMsg( QStringLiteral( "Cannot get pipe projector" ) );
return;
return QString();
}
projector->setCrs( rasterLayer->crs(), d.outputCrs() );
}

if ( !pipe->last() )
{
return;
return QString();
}
fileWriter.setCreateOptions( d.createOptions() );

Expand Down Expand Up @@ -7309,26 +7310,28 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
} );

QgsApplication::taskManager()->addTask( writerTask );
return d.outputFileName();
}


void QgisApp::saveAsFile( QgsMapLayer *layer, bool onlySelected )
QString QgisApp::saveAsFile( QgsMapLayer *layer, const bool onlySelected, const bool defaultToAddToMap )
{
if ( !layer )
layer = activeLayer();

if ( !layer )
return;
return QString();

QgsMapLayer::LayerType layerType = layer->type();
if ( layerType == QgsMapLayer::RasterLayer )
{
saveAsRasterFile( qobject_cast<QgsRasterLayer *>( layer ) );
return saveAsRasterFile( qobject_cast<QgsRasterLayer *>( layer ), defaultToAddToMap );
}
else if ( layerType == QgsMapLayer::VectorLayer )
{
saveAsVectorFileGeneral( qobject_cast<QgsVectorLayer *>( layer ), true, onlySelected );
return saveAsVectorFileGeneral( qobject_cast<QgsVectorLayer *>( layer ), true, onlySelected, defaultToAddToMap );
}
return QString();
}

void QgisApp::makeMemoryLayerPermanent( QgsVectorLayer *layer )
Expand Down Expand Up @@ -7371,7 +7374,7 @@ void QgisApp::makeMemoryLayerPermanent( QgsVectorLayer *layer )
}
};

saveAsVectorFileGeneral( layer, true, false, onSuccess, onFailure, 0, tr( "Save Scratch Layer" ) );
saveAsVectorFileGeneral( layer, true, false, true, onSuccess, onFailure, 0, tr( "Save Scratch Layer" ) );
}

void QgisApp::saveAsLayerDefinition()
Expand Down Expand Up @@ -7475,15 +7478,15 @@ QgisAppFieldValueConverter *QgisAppFieldValueConverter::clone() const

///@endcond

void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected )
QString QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected, bool defaultToAddToMap )
{
if ( !vlayer )
{
vlayer = qobject_cast<QgsVectorLayer *>( activeLayer() ); // FIXME: output of multiple layers at once?
}

if ( !vlayer )
return;
return QString();

const QString layerId = vlayer->id();

Expand Down Expand Up @@ -7521,10 +7524,10 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
}
};

saveAsVectorFileGeneral( vlayer, symbologyOption, onlySelected, onSuccess, onFailure );
return saveAsVectorFileGeneral( vlayer, symbologyOption, onlySelected, defaultToAddToMap, 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, int options, const QString &dialogTitle )
QString QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected, bool defaultToAddToMap, const std::function<void( const QString &, bool, const QString &, const QString &, const QString & )> &onSuccess, const std::function<void ( int, const QString & )> &onFailure, int options, const QString &dialogTitle )
{
QgsCoordinateReferenceSystem destCRS;

Expand All @@ -7540,11 +7543,13 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
dialog->setMapCanvas( mMapCanvas );
dialog->setIncludeZ( QgsWkbTypes::hasZ( vlayer->wkbType() ) );
dialog->setOnlySelected( onlySelected );
dialog->setAddToCanvas( defaultToAddToMap );

QString vectorFilename;
if ( dialog->exec() == QDialog::Accepted )
{
QString encoding = dialog->encoding();
QString vectorFilename = dialog->filename();
vectorFilename = dialog->filename();
QString format = dialog->format();
QStringList datasourceOptions = dialog->datasourceOptions();
bool autoGeometryType = dialog->automaticGeometryType();
Expand Down Expand Up @@ -7612,6 +7617,7 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
}

delete dialog;
return vectorFilename;
}

void QgisApp::layerProperties()
Expand Down
22 changes: 11 additions & 11 deletions src/app/qgisapp.h
Expand Up @@ -703,7 +703,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

public slots:
//! save current vector layer
void saveAsFile( QgsMapLayer *layer = nullptr, bool onlySelected = false );
QString saveAsFile( QgsMapLayer *layer = nullptr, bool onlySelected = false, bool defaultToAddToMap = true );

/**
* Makes a memory layer permanent, by prompting users to save the layer to a disk-based (OGR)
Expand All @@ -716,7 +716,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! save qrl definition for the current layer
void saveAsLayerDefinition();
//! save current raster layer
void saveAsRasterFile( QgsRasterLayer *layer = nullptr );
QString saveAsRasterFile( QgsRasterLayer *layer = nullptr, bool defaultAddToCanvas = true );
//! Process the list of URIs that have been dropped in QGIS
void handleDropUriList( const QgsMimeDataUtils::UriList &lst );
//! Convenience function to open either a project or a layer file.
Expand Down Expand Up @@ -1841,16 +1841,16 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

void setLayoutAtlasFeature( QgsPrintLayout *layout, QgsMapLayer *layer, const QgsFeature &feat );

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

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,
int dialogOptions = QgsVectorLayerSaveAsDialog::AllOptions,
const QString &dialogTitle = QString() );
QString saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected, bool defaultToAddToMap,
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,
int dialogOptions = QgsVectorLayerSaveAsDialog::AllOptions,
const QString &dialogTitle = QString() );

//! Sets project properties, including map untis
void projectProperties( const QString &currentPage = QString() );
Expand Down
11 changes: 11 additions & 0 deletions src/app/qgsappwindowmanager.cpp
Expand Up @@ -18,6 +18,7 @@
#include "qgsstyle.h"
#include "qgisapp.h"
#include "qgslayoutmanagerdialog.h"
#include "qgsrasterlayer.h"

QgsAppWindowManager::~QgsAppWindowManager()
{
Expand Down Expand Up @@ -46,6 +47,16 @@ QWidget *QgsAppWindowManager::openStandardDialog( QgsWindowManagerInterface::Sta
return nullptr;
}

QString QgsAppWindowManager::executeExportVectorLayerDialog( QgsVectorLayer *layer )
{
return QgisApp::instance()->saveAsFile( layer, false, false );
}

QString QgsAppWindowManager::executeExportRasterLayerDialog( QgsRasterLayer *layer )
{
return QgisApp::instance()->saveAsFile( layer, false, false );
}

QWidget *QgsAppWindowManager::openApplicationDialog( QgsAppWindowManager::ApplicationDialog dialog )
{
switch ( dialog )
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsappwindowmanager.h
Expand Up @@ -41,6 +41,8 @@ class QgsAppWindowManager : public QgsWindowManagerInterface
~QgsAppWindowManager();

QWidget *openStandardDialog( QgsWindowManagerInterface::StandardDialog dialog ) override;
QString executeExportVectorLayerDialog( QgsVectorLayer *layer ) override;
QString executeExportRasterLayerDialog( QgsRasterLayer *layer ) override;

/**
* Opens an instance of a application QGIS dialog. Depending on the dialog,
Expand Down
5 changes: 5 additions & 0 deletions src/gui/ogr/qgsvectorlayersaveasdialog.cpp
Expand Up @@ -861,6 +861,11 @@ bool QgsVectorLayerSaveAsDialog::addToCanvas() const
return mAddToCanvas->isChecked();
}

void QgsVectorLayerSaveAsDialog::setAddToCanvas( bool enabled )
{
mAddToCanvas->setChecked( enabled );
}

int QgsVectorLayerSaveAsDialog::symbologyExport() const
{
return mSymbologyExportComboBox->currentData().toInt();
Expand Down
14 changes: 14 additions & 0 deletions src/gui/ogr/qgsvectorlayersaveasdialog.h
Expand Up @@ -65,8 +65,22 @@ class GUI_EXPORT QgsVectorLayerSaveAsDialog : public QDialog, private Ui::QgsVec
QgsAttributeList selectedAttributes() const;
//! Returns selected attributes that must be exported with their displayed values instead of their raw values. Added in QGIS 2.16
QgsAttributeList attributesAsDisplayedValues() const;

/**
* Returns true if the "add to canvas" checkbox is checked.
*
* \see setAddToCanvas()
*/
bool addToCanvas() const;

/**
* Sets whether the "add to canvas" checkbox should be \a checked.
*
* \see addToCanvas()
* \since QGIS 3.6
*/
void setAddToCanvas( bool checked );

/**
* Returns type of symbology export.
0: No symbology
Expand Down

0 comments on commit 7ac5215

Please sign in to comment.