Skip to content

Commit

Permalink
Add flags to QgsVectorFileWriter methods which return lists of drivers
Browse files Browse the repository at this point in the history
Initially only flag available is whether to sort drivers by
recommended order. The recommended order puts GPKG first and
SHP second, then leaves the rest alphabetical.

This fixes a few instances in the QGIS gui where these recommended formats
are not listed first.
  • Loading branch information
nyalldawson committed Nov 5, 2017
1 parent eb6f64e commit dc341d2
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 65 deletions.
47 changes: 37 additions & 10 deletions python/core/qgsvectorfilewriter.sip
Expand Up @@ -145,6 +145,14 @@ Some formats require a compulsory encoding, typically UTF-8. If no compulsory en
SymbolLayerSymbology
};


enum VectorFormatOption
{
SortRecommended,
};
typedef QFlags<QgsVectorFileWriter::VectorFormatOption> VectorFormatOptions;


class FieldValueConverter
{
%Docstring
Expand Down Expand Up @@ -460,27 +468,41 @@ Create a new vector file writer



static QMap< QString, QString> supportedFiltersAndFormats();
static QList< QPair< QString, QString > > supportedFiltersAndFormats( VectorFormatOptions options = SortRecommended );
%Docstring
Returns a map with format filter string as key and OGR format key as value.
Returns a list or pairs, with format filter string as first element and OGR format key as second element.

The ``options`` argument can be used to control the sorting and filtering of
returned formats.

.. seealso:: supportedOutputVectorLayerExtensions()
:rtype: QMap< str, QString>
:rtype: list of QPair< str, QString >
%End

static QStringList supportedFormatExtensions();
static QStringList supportedFormatExtensions( VectorFormatOptions options = SortRecommended );
%Docstring
Returns a list of file extensions for supported formats.

The ``options`` argument can be used to control the sorting and filtering of
returned formats.

.. versionadded:: 3.0
.. seealso:: supportedFiltersAndFormats()
:rtype: list of str
%End

static QMap< QString, QString> ogrDriverList();
static QList< QPair< QString, QString > > ogrDriverList( VectorFormatOptions options = SortRecommended );
%Docstring
Returns driver list that can be used for dialogs. It contains all OGR drivers
+ some additional internal QGIS driver names to distinguish between more
supported formats of the same OGR driver
:rtype: QMap< str, QString>
plus some additional internal QGIS driver names to distinguish between more
supported formats of the same OGR driver.

The returned list consists of pairs of driver long name (e.g. user-friendly
display name for the format) to internal driver short name.

The ``options`` argument can be used to control the sorting and filtering of
returned drivers.
:rtype: list of QPair< str, QString >
%End

static QString driverForExtension( const QString &extension );
Expand All @@ -492,9 +514,12 @@ Create a new vector file writer
:rtype: str
%End

static QString fileFilterString();
static QString fileFilterString( VectorFormatOptions options = SortRecommended );
%Docstring
Returns filter string that can be used for dialogs
Returns filter string that can be used for dialogs.

The ``options`` argument can be used to control the sorting and filtering of
returned drivers.
:rtype: str
%End

Expand Down Expand Up @@ -639,6 +664,8 @@ Close opened shapefile for writing

QFlags<QgsVectorFileWriter::EditionCapability> operator|(QgsVectorFileWriter::EditionCapability f1, QFlags<QgsVectorFileWriter::EditionCapability> f2);

QFlags<QgsVectorFileWriter::VectorFormatOption> operator|(QgsVectorFileWriter::VectorFormatOption f1, QFlags<QgsVectorFileWriter::VectorFormatOption> f2);



/************************************************************************
Expand Down
6 changes: 3 additions & 3 deletions python/plugins/processing/algs/gdal/GdalUtils.py
Expand Up @@ -174,9 +174,9 @@ def getVectorDriverFromFileName(filename):
return 'ESRI Shapefile'

formats = QgsVectorFileWriter.supportedFiltersAndFormats()
for k, v in list(formats.items()):
if ext in k:
return v
for format in formats:
if ext in format[0]:
return format[1]
return 'ESRI Shapefile'

@staticmethod
Expand Down
102 changes: 68 additions & 34 deletions src/core/qgsvectorfilewriter.cpp
Expand Up @@ -2681,13 +2681,16 @@ void QgsVectorFileWriter::setSymbologyScale( double d )
mRenderContext.setRendererScale( mSymbologyScale );
}

QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
QList< QPair< QString, QString > > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
{
QMap<QString, QString> resultMap;
QList< QPair< QString, QString > > resultMap;

QgsApplication::registerOgrDrivers();
int const drvCount = OGRGetDriverCount();

QPair< QString, QString > shapeFormat;
QPair< QString, QString > gpkgFormat;

for ( int i = 0; i < drvCount; ++i )
{
OGRSFDriverH drv = OGRGetDriver( i );
Expand All @@ -2700,51 +2703,68 @@ QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
if ( filterString.isEmpty() )
continue;

resultMap.insert( filterString, drvName );
if ( options & SortRecommended )
{
if ( drvName == QStringLiteral( "ESRI Shapefile" ) )
{
shapeFormat = qMakePair( filterString, drvName );
continue;
}
else if ( drvName == QStringLiteral( "GPKG" ) )
{
gpkgFormat = qMakePair( filterString, drvName );
continue;
}
}
resultMap << qMakePair( filterString, drvName );
}
}
}

std::sort( resultMap.begin(), resultMap.end(), []( const QPair< QString, QString > &a, const QPair< QString, QString > &b ) -> bool
{
return a.second < b.second;
} );

if ( options & SortRecommended )
{
if ( !shapeFormat.first.isEmpty() )
{
resultMap.insert( 0, shapeFormat );
}
if ( !gpkgFormat.first.isEmpty() )
{
resultMap.insert( 0, gpkgFormat );
}
}

return resultMap;
}

QStringList QgsVectorFileWriter::supportedFormatExtensions()
QStringList QgsVectorFileWriter::supportedFormatExtensions( const VectorFormatOptions options )
{
QgsStringMap formats = supportedFiltersAndFormats();
const auto formats = supportedFiltersAndFormats( options );
QStringList extensions;

QRegularExpression rx( QStringLiteral( "\\*\\.([a-zA-Z0-9]*)" ) );

QgsStringMap::const_iterator formatIt = formats.constBegin();
auto formatIt = formats.constBegin();
for ( ; formatIt != formats.constEnd(); ++formatIt )
{
QString ext = formatIt.key();
QString ext = formatIt->first;
QRegularExpressionMatch match = rx.match( ext );
if ( !match.hasMatch() )
continue;

QString matched = match.captured( 1 );

// special handling for the two main contenders for glory
if ( matched.compare( QStringLiteral( "gpkg" ), Qt::CaseInsensitive ) == 0 )
continue;
if ( matched.compare( QStringLiteral( "shp" ), Qt::CaseInsensitive ) == 0 )
continue;

extensions << matched;
}

std::sort( extensions.begin(), extensions.end() );

// Make https://twitter.com/shapefiIe a sad little fellow
extensions.insert( 0, QStringLiteral( "gpkg" ) );
extensions.insert( 1, QStringLiteral( "shp" ) );
return extensions;
}

QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
QList< QPair< QString, QString> > QgsVectorFileWriter::ogrDriverList( const VectorFormatOptions options )
{
QMap<QString, QString> resultMap;
QList< QPair< QString, QString> > resultMap;

QgsApplication::registerOgrDrivers();
int const drvCount = OGRGetDriverCount();
Expand All @@ -2756,6 +2776,10 @@ QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
if ( drv )
{
QString drvName = OGR_Dr_GetName( drv );
if ( drvName == QLatin1String( "ESRI Shapefile" ) )
{
writableDrivers << QStringLiteral( "DBF file" );
}
if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
{
// Add separate format for Mapinfo MIF (MITAB is OGR default)
Expand Down Expand Up @@ -2786,24 +2810,35 @@ QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
}
CPLFree( options[0] );
}
else if ( drvName == QLatin1String( "ESRI Shapefile" ) )
{
writableDrivers << QStringLiteral( "DBF file" );
}
writableDrivers << drvName;
}
}
}
std::sort( writableDrivers.begin(), writableDrivers.end() );
if ( options & SortRecommended )
{
// recommended order sorting, so we shift certain formats to the top
if ( writableDrivers.contains( QStringLiteral( "ESRI Shapefile" ) ) )
{
writableDrivers.removeAll( QStringLiteral( "ESRI Shapefile" ) );
writableDrivers.insert( 0, QStringLiteral( "ESRI Shapefile" ) );
}
if ( writableDrivers.contains( QStringLiteral( "GPKG" ) ) )
{
// Make https://twitter.com/shapefiIe a sad little fellow
writableDrivers.removeAll( QStringLiteral( "GPKG" ) );
writableDrivers.insert( 0, QStringLiteral( "GPKG" ) );
}
}

Q_FOREACH ( const QString &drvName, writableDrivers )
for ( const QString &drvName : qgis::as_const( writableDrivers ) )
{
MetaData metadata;
if ( driverMetadata( drvName, metadata ) && !metadata.trLongName.isEmpty() )
{
resultMap.insert( metadata.trLongName, drvName );
resultMap << qMakePair( metadata.trLongName, drvName );
}
}

return resultMap;
}

Expand Down Expand Up @@ -2841,17 +2876,16 @@ QString QgsVectorFileWriter::driverForExtension( const QString &extension )
return QString();
}

QString QgsVectorFileWriter::fileFilterString()
QString QgsVectorFileWriter::fileFilterString( const VectorFormatOptions options )
{
QString filterString;
QMap< QString, QString> driverFormatMap = supportedFiltersAndFormats();
QMap< QString, QString>::const_iterator it = driverFormatMap.constBegin();
for ( ; it != driverFormatMap.constEnd(); ++it )
const auto driverFormatMap = supportedFiltersAndFormats( options );
for ( auto it = driverFormatMap.constBegin(); it != driverFormatMap.constEnd(); ++it )
{
if ( !filterString.isEmpty() )
filterString += QLatin1String( ";;" );

filterString += it.key();
filterString += it->first;
}
return filterString;
}
Expand Down
47 changes: 39 additions & 8 deletions src/core/qgsvectorfilewriter.h
Expand Up @@ -186,6 +186,17 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
SymbolLayerSymbology //Exports one feature per symbol layer (considering symbol levels)
};


/**
* Options for sorting and filtering vector formats.
* \since QGIS 3.0
*/
enum VectorFormatOption
{
SortRecommended = 1 << 1, //!< Use recommended sort order, with extremely commonly used formats listed first
};
Q_DECLARE_FLAGS( VectorFormatOptions, VectorFormatOption )

/**
* \ingroup core
* Interface to convert raw field values to their user-friendly value.
Expand Down Expand Up @@ -496,24 +507,38 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
QgsVectorFileWriter &operator=( const QgsVectorFileWriter &rh ) = delete;

/**
* Returns a map with format filter string as key and OGR format key as value.
* Returns a list or pairs, with format filter string as first element and OGR format key as second element.
*
* The \a options argument can be used to control the sorting and filtering of
* returned formats.
*
* \see supportedOutputVectorLayerExtensions()
*/
static QMap< QString, QString> supportedFiltersAndFormats();
static QList< QPair< QString, QString > > supportedFiltersAndFormats( VectorFormatOptions options = SortRecommended );

/**
* Returns a list of file extensions for supported formats.
*
* The \a options argument can be used to control the sorting and filtering of
* returned formats.
*
* \since QGIS 3.0
* \see supportedFiltersAndFormats()
*/
static QStringList supportedFormatExtensions();
static QStringList supportedFormatExtensions( VectorFormatOptions options = SortRecommended );

/**
* Returns driver list that can be used for dialogs. It contains all OGR drivers
* + some additional internal QGIS driver names to distinguish between more
* supported formats of the same OGR driver
* plus some additional internal QGIS driver names to distinguish between more
* supported formats of the same OGR driver.
*
* The returned list consists of pairs of driver long name (e.g. user-friendly
* display name for the format) to internal driver short name.
*
* The \a options argument can be used to control the sorting and filtering of
* returned drivers.
*/
static QMap< QString, QString> ogrDriverList();
static QList< QPair< QString, QString > > ogrDriverList( VectorFormatOptions options = SortRecommended );

/**
* Returns the OGR driver name for a specified file \a extension. E.g. the
Expand All @@ -523,8 +548,13 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
*/
static QString driverForExtension( const QString &extension );

//! Returns filter string that can be used for dialogs
static QString fileFilterString();
/**
* Returns filter string that can be used for dialogs.
*
* The \a options argument can be used to control the sorting and filtering of
* returned drivers.
*/
static QString fileFilterString( VectorFormatOptions options = SortRecommended );

//! Creates a filter for an OGR driver key
static QString filterForDriver( const QString &driverName );
Expand Down Expand Up @@ -701,6 +731,7 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
};

Q_DECLARE_OPERATORS_FOR_FLAGS( QgsVectorFileWriter::EditionCapabilities )
Q_DECLARE_OPERATORS_FOR_FLAGS( QgsVectorFileWriter::VectorFormatOptions )

// clazy:excludeall=qstring-allocations

Expand Down
6 changes: 3 additions & 3 deletions src/gui/ogr/qgsvectorlayersaveasdialog.cpp
Expand Up @@ -87,11 +87,11 @@ void QgsVectorLayerSaveAsDialog::setup()
QgsSettings settings;
restoreGeometry( settings.value( QStringLiteral( "Windows/VectorLayerSaveAs/geometry" ) ).toByteArray() );

QMap<QString, QString> map = QgsVectorFileWriter::ogrDriverList();
const QList< QPair< QString, QString > > map = QgsVectorFileWriter::ogrDriverList();
mFormatComboBox->blockSignals( true );
for ( QMap< QString, QString>::const_iterator it = map.constBegin(); it != map.constEnd(); ++it )
for ( auto it = map.constBegin(); it != map.constEnd(); ++it )
{
mFormatComboBox->addItem( it.key(), it.value() );
mFormatComboBox->addItem( it->first, it->second );
}

QString format = settings.value( QStringLiteral( "UI/lastVectorFormat" ), "GPKG" ).toString();
Expand Down

0 comments on commit dc341d2

Please sign in to comment.