From 40443ebb3bb268b053afaeda84f9a7d450d373f3 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Mon, 29 Oct 2018 15:39:35 +1000 Subject: [PATCH] [FEATURE][browser] Add "New" menu to context menu on directories With option to create a new geopackage or shapefile in the clicked directory --- .../qgsnewvectorlayerdialog.sip.in | 17 ++++++++- .../browser/qgsinbuiltdataitemproviders.cpp | 35 +++++++++++++++++-- src/gui/qgsnewvectorlayerdialog.cpp | 16 +++++++-- src/gui/qgsnewvectorlayerdialog.h | 22 ++++++++++-- 4 files changed, 82 insertions(+), 8 deletions(-) diff --git a/python/gui/auto_generated/qgsnewvectorlayerdialog.sip.in b/python/gui/auto_generated/qgsnewvectorlayerdialog.sip.in index 0be7c317ebd..c870a0a047a 100644 --- a/python/gui/auto_generated/qgsnewvectorlayerdialog.sip.in +++ b/python/gui/auto_generated/qgsnewvectorlayerdialog.sip.in @@ -17,10 +17,13 @@ class QgsNewVectorLayerDialog: QDialog %End public: - static QString runAndCreateLayer( QWidget *parent = 0, QString *enc = 0, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ); + static QString runAndCreateLayer( QWidget *parent = 0, QString *enc = 0, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(), + const QString &initialPath = QString() ); %Docstring Runs the dialog and creates a layer matching the dialog parameters. +If the ``initialPath`` argument is specified, then the dialog will default to the specified filename. + :return: fileName on success, empty string use aborted, QString() if creation failed %End @@ -42,9 +45,21 @@ Returns the file format for storage %Docstring Returns the file format for storage %End + QString filename() const; %Docstring Returns the name for the new layer + +.. seealso:: :py:func:`setFilename` +%End + + void setFilename( const QString &filename ); +%Docstring +Sets the initial file name to show in the dialog. + +.. seealso:: :py:func:`filename` + +.. versionadded:: 3.6 %End QgsCoordinateReferenceSystem crs() const; diff --git a/src/app/browser/qgsinbuiltdataitemproviders.cpp b/src/app/browser/qgsinbuiltdataitemproviders.cpp index 2f364d52782..290da9ca1a7 100644 --- a/src/app/browser/qgsinbuiltdataitemproviders.cpp +++ b/src/app/browser/qgsinbuiltdataitemproviders.cpp @@ -27,6 +27,8 @@ #include "qgsbrowserdockwidget_p.h" #include "qgswindowmanagerinterface.h" #include "qgsrasterlayer.h" +#include "qgsnewvectorlayerdialog.h" +#include "qgsnewgeopackagelayerdialog.h" #include #include #include @@ -47,8 +49,9 @@ void QgsAppDirectoryItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe QgsSettings settings; + QMenu *newMenu = new QMenu( tr( "New" ), menu ); - QAction *createFolder = new QAction( tr( "New Directory…" ), menu ); + QAction *createFolder = new QAction( tr( "Directory…" ), menu ); connect( createFolder, &QAction::triggered, this, [ = ] { bool ok = false; @@ -71,7 +74,34 @@ void QgsAppDirectoryItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe } } } ); - menu->addAction( createFolder ); + newMenu->addAction( createFolder ); + + QAction *createGpkg = new QAction( tr( "GeoPackage…" ), newMenu ); + createGpkg->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionNewGeoPackageLayer.svg" ) ) ); + connect( createGpkg, &QAction::triggered, this, [ = ] + { + QgsNewGeoPackageLayerDialog dialog( QgisApp::instance() ); + QDir dir( directoryItem->dirPath() ); + dialog.setDatabasePath( dir.filePath( QStringLiteral( "new_geopackage" ) ) ); + dialog.setCrs( QgsProject::instance()->defaultCrsForNewLayers() ); + if ( dialog.exec() ) + item->refresh(); + } ); + newMenu->addAction( createGpkg ); + + QAction *createShp = new QAction( tr( "ShapeFile…" ), newMenu ); + createShp->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mActionNewVectorLayer.svg" ) ) ); + connect( createShp, &QAction::triggered, this, [ = ] + { + QString enc; + QDir dir( directoryItem->dirPath() ); + const QString newFile = QgsNewVectorLayerDialog::runAndCreateLayer( QgisApp::instance(), &enc, QgsProject::instance()->defaultCrsForNewLayers(), dir.filePath( QStringLiteral( "new_layer.shp" ) ) ); + if ( !newFile.isEmpty() ) + item->refresh(); + } ); + newMenu->addAction( createShp ); + + menu->addMenu( newMenu ); menu->addSeparator(); @@ -97,7 +127,6 @@ void QgsAppDirectoryItemGuiProvider::populateContextMenu( QgsDataItem *item, QMe renameFavorite( favoriteItem ); } ); menu->addAction( actionRename ); - menu->addSeparator(); QAction *removeFavoriteAction = new QAction( tr( "Remove Favorite" ), menu ); connect( removeFavoriteAction, &QAction::triggered, this, [ = ] { diff --git a/src/gui/qgsnewvectorlayerdialog.cpp b/src/gui/qgsnewvectorlayerdialog.cpp index 1514804202f..b867b4fa3c7 100644 --- a/src/gui/qgsnewvectorlayerdialog.cpp +++ b/src/gui/qgsnewvectorlayerdialog.cpp @@ -30,7 +30,7 @@ #include #include #include - +#include QgsNewVectorLayerDialog::QgsNewVectorLayerDialog( QWidget *parent, Qt::WindowFlags fl ) : QDialog( parent, fl ) @@ -104,6 +104,7 @@ QgsNewVectorLayerDialog::QgsNewVectorLayerDialog( QWidget *parent, Qt::WindowFla mFileName->setStorageMode( QgsFileWidget::SaveFile ); mFileName->setFilter( QgsVectorFileWriter::filterForDriver( mFileFormatComboBox->currentData( Qt::UserRole ).toString() ) ); + mFileName->setConfirmOverwrite( false ); mFileName->setDialogTitle( tr( "Save Layer As" ) ); mFileName->setDefaultRoot( settings.value( QStringLiteral( "UI/lastVectorFileFilterDir" ), QDir::homePath() ).toString() ); connect( mFileName, &QgsFileWidget::fileChanged, this, [ = ] @@ -245,6 +246,11 @@ QString QgsNewVectorLayerDialog::filename() const return mFileName->filePath(); } +void QgsNewVectorLayerDialog::setFilename( const QString &filename ) +{ + mFileName->setFilePath( filename ); +} + void QgsNewVectorLayerDialog::checkOk() { bool ok = ( !mFileName->filePath().isEmpty() && mAttributeView->topLevelItemCount() > 0 ); @@ -252,15 +258,21 @@ void QgsNewVectorLayerDialog::checkOk() } // this is static -QString QgsNewVectorLayerDialog::runAndCreateLayer( QWidget *parent, QString *pEnc, const QgsCoordinateReferenceSystem &crs ) +QString QgsNewVectorLayerDialog::runAndCreateLayer( QWidget *parent, QString *pEnc, const QgsCoordinateReferenceSystem &crs, const QString &initialPath ) { QgsNewVectorLayerDialog geomDialog( parent ); geomDialog.setCrs( crs ); + if ( !initialPath.isEmpty() ) + geomDialog.setFilename( initialPath ); if ( geomDialog.exec() == QDialog::Rejected ) { return QString(); } + if ( QFile::exists( geomDialog.filename() ) && QMessageBox::warning( parent, tr( "New ShapeFile Layer" ), tr( "The layer already exists. Are you sure you want to overwrite the existing file?" ), + QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Cancel ) != QMessageBox::Yes ) + return QString(); + QgsWkbTypes::Type geometrytype = geomDialog.selectedType(); QString fileformat = geomDialog.selectedFileFormat(); QString enc = geomDialog.selectedFileEncoding(); diff --git a/src/gui/qgsnewvectorlayerdialog.h b/src/gui/qgsnewvectorlayerdialog.h index 06dc5d5017d..b352f19df40 100644 --- a/src/gui/qgsnewvectorlayerdialog.h +++ b/src/gui/qgsnewvectorlayerdialog.h @@ -36,9 +36,13 @@ class GUI_EXPORT QgsNewVectorLayerDialog: public QDialog, private Ui::QgsNewVect /** * Runs the dialog and creates a layer matching the dialog parameters. + * + * If the \a initialPath argument is specified, then the dialog will default to the specified filename. + * * \returns fileName on success, empty string use aborted, QString() if creation failed */ - static QString runAndCreateLayer( QWidget *parent = nullptr, QString *enc = nullptr, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() ); + static QString runAndCreateLayer( QWidget *parent = nullptr, QString *enc = nullptr, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(), + const QString &initialPath = QString() ); QgsNewVectorLayerDialog( QWidget *parent SIP_TRANSFERTHIS = nullptr, Qt::WindowFlags fl = QgsGuiUtils::ModalDialogFlags ); ~QgsNewVectorLayerDialog() override; @@ -50,9 +54,23 @@ class GUI_EXPORT QgsNewVectorLayerDialog: public QDialog, private Ui::QgsNewVect QString selectedFileFormat() const; //! Returns the file format for storage QString selectedFileEncoding() const; - //! Returns the name for the new layer + + /** + * Returns the name for the new layer + * + * \see setFilename() + */ QString filename() const; + /** + * Sets the initial file name to show in the dialog. + * + * \see filename() + * + * \since QGIS 3.6 + */ + void setFilename( const QString &filename ); + /** * Returns the selected CRS for the new layer. * \see setCrs()