Skip to content
Permalink
Browse files

New Shapefile Layer dialog: avoid warning message on user cancel

Also add better error message reporting, and deprecate horrible API.

(cherry picked from commit 9a723d9)
  • Loading branch information
nyalldawson committed Feb 1, 2019
1 parent dbd7512 commit a6cad4dfa302d63db527d44a71a88c32a9696851
@@ -17,14 +17,46 @@ 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() ) /Deprecated/;
%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

.. deprecated:: in QGIS 3.4.5 - use execAndCreateLayer() instead.
%End

static QString execAndCreateLayer( QString &errorMessage /Out/, QWidget *parent = 0, const QString &initialPath = QString(), QString *encoding /Out/ = 0, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
%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.

Returns a filename if the dialog was accepted, or an empty string if the dialog was canceled.
If the dialog was accepted but an error occurred while creating the file, then the function will
return an empty string and ``errorMessage`` will contain the error message.

If ``encoding`` is specified, it will be set to the encoding of the created file.

:param errorMessage: will be set to any error message encountered during layer creation
:param parent: parent widget for dialog
:param initialPath: initial file path to show in dialog
:param encoding: if specified, will be set to file encoding of created layer
:param crs: default layer CRS to show in dialog

:return: Newly created file name, or an empty string if user canceled or an error occurred.


.. versionadded:: 3.4.5
%End

QgsNewVectorLayerDialog( QWidget *parent /TransferThis/ = 0, Qt::WindowFlags fl = QgsGuiUtils::ModalDialogFlags );
%Docstring
New dialog constructor.
%End
~QgsNewVectorLayerDialog();
QgsWkbTypes::Type selectedType() const;
%Docstring
@@ -42,9 +74,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.4.5
%End

QgsCoordinateReferenceSystem crs() const;
@@ -5602,7 +5602,8 @@ void QgisApp::fileNewFromTemplateAction( QAction *qAction )
void QgisApp::newVectorLayer()
{
QString enc;
QString fileName = QgsNewVectorLayerDialog::runAndCreateLayer( this, &enc, QgsProject::instance()->defaultCrsForNewLayers() );
QString error;
QString fileName = QgsNewVectorLayerDialog::execAndCreateLayer( error, this, QString(), &enc, QgsProject::instance()->defaultCrsForNewLayers() );

if ( !fileName.isEmpty() )
{
@@ -5612,12 +5613,12 @@ void QgisApp::newVectorLayer()
//todo: the last parameter will change accordingly to layer type
addVectorLayers( fileNames, enc, QStringLiteral( "file" ) );
}
else if ( fileName.isNull() )
else if ( !error.isEmpty() )
{
QLabel *msgLabel = new QLabel( tr( "Layer creation failed. Please check the <a href=\"#messageLog\">message log</a> for further information." ), messageBar() );
QLabel *msgLabel = new QLabel( tr( "Layer creation failed: %1" ).arg( error ), messageBar() );
msgLabel->setWordWrap( true );
connect( msgLabel, &QLabel::linkActivated, mLogDock, &QWidget::show );
QgsMessageBarItem *item = new QgsMessageBarItem( msgLabel, Qgis::Warning );
QgsMessageBarItem *item = new QgsMessageBarItem( msgLabel, Qgis::Critical );
messageBar()->pushItem( item );
}
}
@@ -30,7 +30,7 @@
#include <QComboBox>
#include <QLibrary>
#include <QFileDialog>

#include <QMessageBox>

QgsNewVectorLayerDialog::QgsNewVectorLayerDialog( QWidget *parent, Qt::WindowFlags fl )
: QDialog( parent, fl )
@@ -105,6 +105,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, [ = ]
@@ -246,22 +247,43 @@ 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 );
mOkButton->setEnabled( ok );
}

// 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 )
{
QString error;
QString res = execAndCreateLayer( error, parent, initialPath, pEnc, crs );
if ( res.isEmpty() && error.isEmpty() )
res = QString( "" ); // maintain gross earlier API compatibility
return res;
}

QString QgsNewVectorLayerDialog::execAndCreateLayer( QString &errorMessage, QWidget *parent, const QString &initialPath, QString *encoding, const QgsCoordinateReferenceSystem &crs )
{
errorMessage.clear();
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();
@@ -289,33 +311,35 @@ QString QgsNewVectorLayerDialog::runAndCreateLayer( QWidget *parent, QString *pE
QgsDebugMsg( QStringLiteral( "ogr provider loaded" ) );

typedef bool ( *createEmptyDataSourceProc )( const QString &, const QString &, const QString &, QgsWkbTypes::Type,
const QList< QPair<QString, QString> > &, const QgsCoordinateReferenceSystem & );
const QList< QPair<QString, QString> > &, const QgsCoordinateReferenceSystem &, QString & );
createEmptyDataSourceProc createEmptyDataSource = ( createEmptyDataSourceProc ) cast_to_fptr( myLib->resolve( "createEmptyDataSource" ) );
if ( createEmptyDataSource )
{
if ( geometrytype != QgsWkbTypes::Unknown )
{
QgsCoordinateReferenceSystem srs = geomDialog.crs();
if ( !createEmptyDataSource( fileName, fileformat, enc, geometrytype, attributes, srs ) )
if ( !createEmptyDataSource( fileName, fileformat, enc, geometrytype, attributes, srs, errorMessage ) )
{
return QString();
}
}
else
{
QgsDebugMsg( QStringLiteral( "geometry type not recognised" ) );
errorMessage = QObject::tr( "Geometry type not recognised" );
QgsDebugMsg( errorMessage );
return QString();
}
}
else
{
QgsDebugMsg( QStringLiteral( "Resolving newEmptyDataSource(...) failed" ) );
errorMessage = QObject::tr( "Resolving newEmptyDataSource(...) failed" );
QgsDebugMsg( errorMessage );
return QString();
}
}

if ( pEnc )
*pEnc = enc;
if ( encoding )
*encoding = enc;

return fileName;
}
@@ -324,3 +348,4 @@ void QgsNewVectorLayerDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-shapefile-layer" ) );
}

@@ -21,8 +21,9 @@
#include "qgsguiutils.h"
#include "qgshelp.h"

#include "qgis.h"
#include "qgswkbtypes.h"
#include "qgis_gui.h"
#include "qgis_sip.h"

/**
* \ingroup gui
@@ -36,10 +37,42 @@ 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
*
* \deprecated in QGIS 3.4.5 - use execAndCreateLayer() instead.
*/
static QString runAndCreateLayer( QWidget *parent = nullptr, QString *enc = nullptr, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );
Q_DECL_DEPRECATED static QString runAndCreateLayer( QWidget *parent = nullptr, QString *enc = nullptr, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem(),
const QString &initialPath = QString() ) SIP_DEPRECATED;

/**
* 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 a filename if the dialog was accepted, or an empty string if the dialog was canceled.
* If the dialog was accepted but an error occurred while creating the file, then the function will
* return an empty string and \a errorMessage will contain the error message.
*
* If \a encoding is specified, it will be set to the encoding of the created file.
*
* \param errorMessage will be set to any error message encountered during layer creation
* \param parent parent widget for dialog
* \param initialPath initial file path to show in dialog
* \param encoding if specified, will be set to file encoding of created layer
* \param crs default layer CRS to show in dialog
*
* \returns Newly created file name, or an empty string if user canceled or an error occurred.
*
* \since QGIS 3.4.5
*/
static QString execAndCreateLayer( QString &errorMessage SIP_OUT, QWidget *parent = nullptr, const QString &initialPath = QString(), QString *encoding SIP_OUT = nullptr, const QgsCoordinateReferenceSystem &crs = QgsCoordinateReferenceSystem() );

/**
* New dialog constructor.
*/
QgsNewVectorLayerDialog( QWidget *parent SIP_TRANSFERTHIS = nullptr, Qt::WindowFlags fl = QgsGuiUtils::ModalDialogFlags );
~QgsNewVectorLayerDialog() override;
//! Returns the selected geometry type
@@ -50,9 +83,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.4.5
*/
void setFilename( const QString &filename );

/**
* Returns the selected CRS for the new layer.
* \see setCrs()
@@ -261,13 +261,14 @@ bool QgsGeometryCheckerResultTab::exportErrorsDo( const QString &file )
{
return false;
}
typedef bool ( *createEmptyDataSourceProc )( const QString &, const QString &, const QString &, QgsWkbTypes::Type, const QList< QPair<QString, QString> > &, const QgsCoordinateReferenceSystem & );
typedef bool ( *createEmptyDataSourceProc )( const QString &, const QString &, const QString &, QgsWkbTypes::Type, const QList< QPair<QString, QString> > &, const QgsCoordinateReferenceSystem &, QString & );
createEmptyDataSourceProc createEmptyDataSource = ( createEmptyDataSourceProc ) cast_to_fptr( ogrLib.resolve( "createEmptyDataSource" ) );
if ( !createEmptyDataSource )
{
return false;
}
if ( !createEmptyDataSource( file, driver, "UTF-8", QgsWkbTypes::Point, attributes, QgsProject::instance()->crs() ) )
QString createError;
if ( !createEmptyDataSource( file, driver, "UTF-8", QgsWkbTypes::Point, attributes, QgsProject::instance()->crs(), createError ) )
{
return false;
}
@@ -3183,9 +3183,11 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
const QString &encoding,
QgsWkbTypes::Type vectortype,
const QList< QPair<QString, QString> > &attributes,
const QgsCoordinateReferenceSystem &srs = QgsCoordinateReferenceSystem() )
const QgsCoordinateReferenceSystem &srs,
QString &errorMessage )
{
QgsDebugMsg( QStringLiteral( "Creating empty vector layer with format: %1" ).arg( format ) );
errorMessage.clear();

QgsApplication::registerOgrDrivers();
OGRSFDriverH driver = OGRGetDriverByName( format.toLatin1() );
@@ -3200,7 +3202,8 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
{
if ( !uri.endsWith( QLatin1String( ".shp" ), Qt::CaseInsensitive ) )
{
QgsDebugMsg( QStringLiteral( "uri %1 doesn't end with .shp" ).arg( uri ) );
errorMessage = QObject::tr( "URI %1 doesn't end with .shp" ).arg( uri );
QgsDebugMsg( errorMessage );
return false;
}

@@ -3212,7 +3215,8 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
QString name = fldIt->first.left( 10 );
if ( fieldNames.contains( name ) )
{
QgsMessageLog::logMessage( QObject::tr( "Duplicate field (10 significant characters): %1" ).arg( name ), QObject::tr( "OGR" ) );
errorMessage = QObject::tr( "Duplicate field (10 significant characters): %1" ).arg( name );
QgsMessageLog::logMessage( errorMessage, QObject::tr( "OGR" ) );
return false;
}
fieldNames << name;
@@ -3229,7 +3233,8 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
dataSource.reset( OGR_Dr_CreateDataSource( driver, uri.toUtf8().constData(), nullptr ) );
if ( !dataSource )
{
QgsMessageLog::logMessage( QObject::tr( "Creating the data source %1 failed: %2" ).arg( uri, QString::fromUtf8( CPLGetLastErrorMsg() ) ), QObject::tr( "OGR" ) );
errorMessage = QObject::tr( "Creating the data source %1 failed: %2" ).arg( uri, QString::fromUtf8( CPLGetLastErrorMsg() ) );
QgsMessageLog::logMessage( errorMessage, QObject::tr( "OGR" ) );
return false;
}

@@ -3263,7 +3268,8 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,
case QgsWkbTypes::GeometryCollectionZM:
case QgsWkbTypes::Unknown:
{
QgsMessageLog::logMessage( QObject::tr( "Unknown vector type of %1" ).arg( ( int )( vectortype ) ), QObject::tr( "OGR" ) );
errorMessage = QObject::tr( "Unknown vector type of %1" ).arg( static_cast< int >( vectortype ) );
QgsMessageLog::logMessage( errorMessage, QObject::tr( "OGR" ) );
return false;
}

@@ -3292,7 +3298,8 @@ QGISEXTERN bool createEmptyDataSource( const QString &uri,

if ( !layer )
{
QgsMessageLog::logMessage( QObject::tr( "Creation of OGR data source %1 failed: %2" ).arg( uri, QString::fromUtf8( CPLGetLastErrorMsg() ) ), QObject::tr( "OGR" ) );
errorMessage = QString::fromUtf8( CPLGetLastErrorMsg() );
QgsMessageLog::logMessage( errorMessage, QObject::tr( "OGR" ) );
return false;
}

0 comments on commit a6cad4d

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