[FEATURE] Add "export to file" options for raster and vector layers

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.
This commit is contained in:
Nyall Dawson 2018-10-11 11:30:37 +10:00
parent 2089887754
commit 7ac521529b
12 changed files with 224 additions and 29 deletions

View File

@ -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;

View File

@ -9,6 +9,7 @@
class QgsWindowManagerInterface
{
%Docstring
@ -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
};

View File

@ -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() );
@ -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();
@ -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
@ -7227,7 +7228,7 @@ void QgisApp::saveAsRasterFile( QgsRasterLayer *rasterLayer )
if ( !pipe->insert( 2, projector ) )
{
QgsDebugMsg( QStringLiteral( "Cannot set pipe projector" ) );
return;
return QString();
}
}
}
@ -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() );
@ -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 )
@ -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()
@ -7475,7 +7478,7 @@ 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 )
{
@ -7483,7 +7486,7 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
}
if ( !vlayer )
return;
return QString();
const QString layerId = vlayer->id();
@ -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;
@ -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();
@ -7612,6 +7617,7 @@ void QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOpt
}
delete dialog;
return vectorFilename;
}
void QgisApp::layerProperties()

View File

@ -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)
@ -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.
@ -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() );

View File

@ -18,6 +18,7 @@
#include "qgsstyle.h"
#include "qgisapp.h"
#include "qgslayoutmanagerdialog.h"
#include "qgsrasterlayer.h"
QgsAppWindowManager::~QgsAppWindowManager()
{
@ -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 )

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -33,6 +33,8 @@
#include "qgssettings.h"
#include "qgsnewnamedialog.h"
#include "qgsbrowserproxymodel.h"
#include "qgsgui.h"
#include "qgswindowmanagerinterface.h"
// browser layer properties dialog
#include "qgsapplication.h"
@ -228,6 +230,45 @@ void QgsBrowserDockWidget::showContextMenu( QPoint pt )
}
else if ( item->type() == QgsDataItem::Layer )
{
QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
if ( layerItem && ( layerItem->mapLayerType() == QgsMapLayer::VectorLayer ||
layerItem->mapLayerType() == QgsMapLayer::RasterLayer ) )
{
QMenu *exportMenu = new QMenu( tr( "Export Layer" ), menu );
menu->addMenu( exportMenu );
QAction *toFileAction = new QAction( tr( "To File…" ), exportMenu );
exportMenu->addAction( toFileAction );
connect( toFileAction, &QAction::triggered, layerItem, [ layerItem ]
{
switch ( layerItem->mapLayerType() )
{
case QgsMapLayer::VectorLayer:
{
std::unique_ptr<QgsVectorLayer> layer( new QgsVectorLayer( layerItem->uri(), layerItem->name(), layerItem->providerKey() ) );
if ( layer && layer->isValid() )
{
QgsGui::instance()->windowManager()->executeExportVectorLayerDialog( layer.get() );
}
break;
}
case QgsMapLayer::RasterLayer:
{
std::unique_ptr<QgsRasterLayer> layer( new QgsRasterLayer( layerItem->uri(), layerItem->name(), layerItem->providerKey() ) );
if ( layer && layer->isValid() )
{
QgsGui::instance()->windowManager()->executeExportRasterLayerDialog( layer.get() );
}
break;
}
case QgsMapLayer::PluginLayer:
case QgsMapLayer::MeshLayer:
break;
}
} );
}
menu->addAction( tr( "Add Selected Layer(s) to Canvas" ), this, SLOT( addSelectedLayers() ) );
menu->addAction( tr( "Properties…" ), this, SLOT( showProperties() ) );
}

View File

@ -378,6 +378,11 @@ bool QgsRasterLayerSaveAsDialog::addToCanvas() const
return mAddToCanvas->isChecked();
}
void QgsRasterLayerSaveAsDialog::setAddToCanvas( bool checked )
{
mAddToCanvas->setChecked( checked );
}
QString QgsRasterLayerSaveAsDialog::outputFileName() const
{
QString fileName = mFilename->filePath();

View File

@ -69,7 +69,22 @@ class GUI_EXPORT QgsRasterLayerSaveAsDialog: public QDialog, private Ui::QgsRast
int maximumTileSizeX() const;
int maximumTileSizeY() const;
bool tileMode() 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 );
QString outputFileName() const;
/**

View File

@ -19,6 +19,9 @@
#include "qgis.h"
#include "qgis_gui.h"
class QgsVectorLayer;
class QgsRasterLayer;
///@cond NOT_STABLE
/**
@ -53,6 +56,48 @@ class GUI_EXPORT QgsWindowManagerInterface
*/
virtual QWidget *openStandardDialog( StandardDialog dialog ) = 0;
/**
* Executes the standard "Export Vector Layer" dialog for the specified \a 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.
*
* \see executeExportRasterLayerDialog()
*
* \since QGIS 3.6
*/
virtual QString executeExportVectorLayerDialog( QgsVectorLayer *layer )
{
Q_UNUSED( layer );
return QString();
}
/**
* Executes the standard "Export Raster Layer" dialog for the specified \a 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.
*
* \see executeExportVectorLayerDialog()
*
* \since QGIS 3.6
*/
virtual QString executeExportRasterLayerDialog( QgsRasterLayer *layer )
{
Q_UNUSED( layer );
return QString();
}
};
///@endcond