Skip to content

Commit

Permalink
Merge pull request #5534 from nyalldawson/format
Browse files Browse the repository at this point in the history
Add flags to QgsVectorFileWriter methods which return lists of drivers
  • Loading branch information
nyalldawson committed Nov 5, 2017
2 parents bfe0355 + 2df5332 commit 31f98da
Show file tree
Hide file tree
Showing 8 changed files with 309 additions and 78 deletions.
2 changes: 2 additions & 0 deletions doc/api_break.dox
Expand Up @@ -2672,6 +2672,8 @@ for consistency with other parts of the QGIS API.
- The addFeature which takes a renderer argument was renamed to addFeatureWithStyle.
- static `writeAsVectorFormat` calls no longer take a errorMessage argument in
python and instead return a `(errorCode, errorMessage)` tuple.
- ogrDriverList now returns a list of QgsVectorFileWriter.DriverDetails structs, instead of a map
- supportedFiltersAndFormats now returns a list of QgsVectorFileWriter.FilterFormatDetails structs, instead of a map


QgsWMSLegendNode {#qgis_api_break_3_0_QgsWMSLegendNode}
Expand Down
78 changes: 65 additions & 13 deletions python/core/qgsvectorfilewriter.sip
Expand Up @@ -10,8 +10,6 @@





class QgsVectorFileWriter : QgsFeatureSink
{
%Docstring
Expand Down Expand Up @@ -145,6 +143,15 @@ Some formats require a compulsory encoding, typically UTF-8. If no compulsory en
SymbolLayerSymbology
};


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


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



static QMap< QString, QString> supportedFiltersAndFormats();
struct FilterFormatDetails
{
QString driverName;
%Docstring
Unique driver name
%End

QString filterString;
%Docstring
Filter string for file picker dialogs
%End
};

static QList< QgsVectorFileWriter::FilterFormatDetails > 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 QgsVectorFileWriter.FilterFormatDetails
%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();
struct DriverDetails
{
QString longName;
%Docstring
Descriptive, user friendly name for the driver
%End

QString driverName;
%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>
Unique driver name
%End
};

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

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

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

static QString driverForExtension( const QString &extension );
Expand All @@ -492,9 +539,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 +689,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.filterString:
return format.driverName
return 'ESRI Shapefile'

@staticmethod
Expand Down
140 changes: 100 additions & 40 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< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
{
QMap<QString, QString> resultMap;
QList< FilterFormatDetails > results;

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

FilterFormatDetails shapeFormat;
FilterFormatDetails gpkgFormat;

for ( int i = 0; i < drvCount; ++i )
{
OGRSFDriverH drv = OGRGetDriver( i );
Expand All @@ -2696,58 +2699,87 @@ QMap< QString, QString> QgsVectorFileWriter::supportedFiltersAndFormats()
QString drvName = OGR_Dr_GetName( drv );
if ( OGR_Dr_TestCapability( drv, "CreateDataSource" ) != 0 )
{
if ( options & SkipNonSpatialFormats )
{
// skip non-spatial formats
// TODO - use GDAL metadata to determine this, when support exists in GDAL
if ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) )
continue;
}

QString filterString = filterForDriver( drvName );
if ( filterString.isEmpty() )
continue;

resultMap.insert( filterString, drvName );
FilterFormatDetails details;
details.driverName = drvName;
details.filterString = filterString;

if ( options & SortRecommended )
{
if ( drvName == QLatin1String( "ESRI Shapefile" ) )
{
shapeFormat = details;
continue;
}
else if ( drvName == QLatin1String( "GPKG" ) )
{
gpkgFormat = details;
continue;
}
}

results << details;
}
}
}

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

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

return results;
}

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();
for ( ; formatIt != formats.constEnd(); ++formatIt )
for ( const FilterFormatDetails &format : formats )
{
QString ext = formatIt.key();
QString ext = format.filterString;
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< QgsVectorFileWriter::DriverDetails > QgsVectorFileWriter::ogrDriverList( const VectorFormatOptions options )
{
QMap<QString, QString> resultMap;
QList< QgsVectorFileWriter::DriverDetails > results;

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

QStringList writableDrivers;
for ( int i = 0; i < drvCount; ++i )
Expand All @@ -2756,6 +2788,19 @@ QMap<QString, QString> QgsVectorFileWriter::ogrDriverList()
if ( drv )
{
QString drvName = OGR_Dr_GetName( drv );

if ( options & SkipNonSpatialFormats )
{
// skip non-spatial formats
// TODO - use GDAL metadata to determine this, when support exists in GDAL
if ( drvName == QLatin1String( "ODS" ) || drvName == QLatin1String( "XLSX" ) || drvName == QLatin1String( "XLS" ) )
continue;
}

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,25 +2831,39 @@ 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 );
DriverDetails details;
details.driverName = drvName;
details.longName = metadata.trLongName;
results << details;
}
}

return resultMap;
return results;
}

QString QgsVectorFileWriter::driverForExtension( const QString &extension )
Expand Down Expand Up @@ -2841,17 +2900,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 driverFormats = supportedFiltersAndFormats( options );
for ( const FilterFormatDetails &details : driverFormats )
{
if ( !filterString.isEmpty() )
filterString += QLatin1String( ";;" );

filterString += it.key();
filterString += details.filterString;
}
return filterString;
}
Expand All @@ -2860,9 +2918,11 @@ QString QgsVectorFileWriter::filterForDriver( const QString &driverName )
{
MetaData metadata;
if ( !driverMetadata( driverName, metadata ) || metadata.trLongName.isEmpty() || metadata.glob.isEmpty() )
return QLatin1String( "" );
return QString();

return metadata.trLongName + " [OGR] (" + metadata.glob.toLower() + ' ' + metadata.glob.toUpper() + ')';
return QStringLiteral( "%1 (%2 %3)" ).arg( metadata.trLongName,
metadata.glob.toLower(),
metadata.glob.toUpper() );
}

QString QgsVectorFileWriter::convertCodecNameForEncodingOption( const QString &codecName )
Expand Down

0 comments on commit 31f98da

Please sign in to comment.