diff --git a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in index 16f8f9abc70..26675d0419a 100644 --- a/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in +++ b/python/gui/auto_generated/qgsrasterlayersaveasdialog.sip.in @@ -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; diff --git a/python/gui/auto_generated/qgswindowmanagerinterface.sip.in b/python/gui/auto_generated/qgswindowmanagerinterface.sip.in index 73a571b1699..f84f8349e65 100644 --- a/python/gui/auto_generated/qgswindowmanagerinterface.sip.in +++ b/python/gui/auto_generated/qgswindowmanagerinterface.sip.in @@ -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 }; diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 6b14aff27a2..687369ad9ba 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -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( 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( layer ) ); + return saveAsRasterFile( qobject_cast( layer ), defaultToAddToMap ); } else if ( layerType == QgsMapLayer::VectorLayer ) { - saveAsVectorFileGeneral( qobject_cast( layer ), true, onlySelected ); + return saveAsVectorFileGeneral( qobject_cast( 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 &onSuccess, const std::function &onFailure, int options, const QString &dialogTitle ) +QString QgisApp::saveAsVectorFileGeneral( QgsVectorLayer *vlayer, bool symbologyOption, bool onlySelected, bool defaultToAddToMap, const std::function &onSuccess, const std::function &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() diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index d8ed42ea978..9f478c72dc8 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -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 ¤tPage = QString() ); diff --git a/src/app/qgsappwindowmanager.cpp b/src/app/qgsappwindowmanager.cpp index 6db10e20484..87e638a0088 100644 --- a/src/app/qgsappwindowmanager.cpp +++ b/src/app/qgsappwindowmanager.cpp @@ -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 ) diff --git a/src/app/qgsappwindowmanager.h b/src/app/qgsappwindowmanager.h index ef71b0901d5..472d7f1a9b8 100644 --- a/src/app/qgsappwindowmanager.h +++ b/src/app/qgsappwindowmanager.h @@ -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, diff --git a/src/gui/ogr/qgsvectorlayersaveasdialog.cpp b/src/gui/ogr/qgsvectorlayersaveasdialog.cpp index 589aa645c27..bbc0aa0abf6 100644 --- a/src/gui/ogr/qgsvectorlayersaveasdialog.cpp +++ b/src/gui/ogr/qgsvectorlayersaveasdialog.cpp @@ -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(); diff --git a/src/gui/ogr/qgsvectorlayersaveasdialog.h b/src/gui/ogr/qgsvectorlayersaveasdialog.h index 2ede1165e0a..a13fc2b6c22 100644 --- a/src/gui/ogr/qgsvectorlayersaveasdialog.h +++ b/src/gui/ogr/qgsvectorlayersaveasdialog.h @@ -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 diff --git a/src/gui/qgsbrowserdockwidget.cpp b/src/gui/qgsbrowserdockwidget.cpp index 3d9748f01cc..2b18afc3282 100644 --- a/src/gui/qgsbrowserdockwidget.cpp +++ b/src/gui/qgsbrowserdockwidget.cpp @@ -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( 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 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 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() ) ); } diff --git a/src/gui/qgsrasterlayersaveasdialog.cpp b/src/gui/qgsrasterlayersaveasdialog.cpp index 77c76a0b38f..4a7a2b1ab79 100644 --- a/src/gui/qgsrasterlayersaveasdialog.cpp +++ b/src/gui/qgsrasterlayersaveasdialog.cpp @@ -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(); diff --git a/src/gui/qgsrasterlayersaveasdialog.h b/src/gui/qgsrasterlayersaveasdialog.h index ac83c0033b3..37319832ae2 100644 --- a/src/gui/qgsrasterlayersaveasdialog.h +++ b/src/gui/qgsrasterlayersaveasdialog.h @@ -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; /** diff --git a/src/gui/qgswindowmanagerinterface.h b/src/gui/qgswindowmanagerinterface.h index 5317d330642..0694e4ccbda 100644 --- a/src/gui/qgswindowmanagerinterface.h +++ b/src/gui/qgswindowmanagerinterface.h @@ -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