Add driver filter option for formats capable of multi-layer storage

This commit is contained in:
Nyall Dawson 2023-05-25 11:45:17 +10:00
parent 33ffe9f6b9
commit a865a762a4
5 changed files with 71 additions and 2 deletions

View File

@ -149,6 +149,7 @@ Constructor for MetaData
{
SortRecommended,
SkipNonSpatialFormats,
SupportsMultipleLayers,
};
typedef QFlags<QgsVectorFileWriter::VectorFormatOption> VectorFormatOptions;

View File

@ -702,6 +702,7 @@ QStringList QgsGdalUtils::multiLayerFileExtensions()
QStringLiteral( "pbf" ),
QStringLiteral( "vrt" ),
QStringLiteral( "nc" ),
QStringLiteral( "dxf" ),
QStringLiteral( "shp.zip" ) };
return SUPPORTED_DB_LAYERS_EXTENSIONS;
#endif

View File

@ -19,6 +19,7 @@
#include "qgsapplication.h"
#include "qgsfields.h"
#include "qgsgdalutils.h"
#include "qgslogger.h"
#include "qgsmessagelog.h"
#include "qgscoordinatereferencesystem.h"
@ -3785,6 +3786,33 @@ void QgsVectorFileWriter::setSymbologyScale( double d )
mRenderContext.setRendererScale( mSymbologyScale );
}
QStringList multiLayerFormats()
{
QStringList driverNames;
const QSet< QString > multiLayerExtensions = qgis::listToSet( QgsGdalUtils::multiLayerFileExtensions() );
for ( int i = 0; i < GDALGetDriverCount(); ++i )
{
GDALDriverH driver = GDALGetDriver( i );
if ( !driver )
{
QgsLogger::warning( "unable to get driver " + QString::number( i ) );
continue;
}
const QString driverExtensions = GDALGetMetadataItem( driver, GDAL_DMD_EXTENSIONS, "" );
if ( driverExtensions.isEmpty() )
continue;
const QSet< QString > splitExtensions = qgis::listToSet( driverExtensions.split( ' ', Qt::SkipEmptyParts ) );
if ( splitExtensions.intersects( multiLayerExtensions ) )
{
driverNames << OGR_Dr_GetName( driver );
}
}
return driverNames;
}
QList< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supportedFiltersAndFormats( const VectorFormatOptions options )
{
static QReadWriteLock sFilterLock;
@ -3802,12 +3830,20 @@ QList< QgsVectorFileWriter::FilterFormatDetails > QgsVectorFileWriter::supported
QgsApplication::registerOgrDrivers();
int const drvCount = OGRGetDriverCount();
const QStringList multiLayerDrivers = multiLayerFormats();
for ( int i = 0; i < drvCount; ++i )
{
OGRSFDriverH drv = OGRGetDriver( i );
if ( drv )
{
QString drvName = OGR_Dr_GetName( drv );
const QString drvName = OGR_Dr_GetName( drv );
if ( options & SupportsMultipleLayers )
{
if ( !multiLayerDrivers.contains( drvName ) )
continue;
}
GDALDriverH gdalDriver = GDALGetDriverByName( drvName.toLocal8Bit().constData() );
char **metadata = nullptr;
@ -3918,13 +3954,21 @@ QList< QgsVectorFileWriter::DriverDetails > QgsVectorFileWriter::ogrDriverList(
QgsApplication::registerOgrDrivers();
const int drvCount = OGRGetDriverCount();
const QStringList multiLayerDrivers = multiLayerFormats();
QStringList writableDrivers;
for ( int i = 0; i < drvCount; ++i )
{
OGRSFDriverH drv = OGRGetDriver( i );
if ( drv )
{
QString drvName = OGR_Dr_GetName( drv );
const QString drvName = OGR_Dr_GetName( drv );
if ( options & SupportsMultipleLayers )
{
if ( !multiLayerDrivers.contains( drvName ) )
continue;
}
if ( options & SkipNonSpatialFormats )
{

View File

@ -199,6 +199,7 @@ class CORE_EXPORT QgsVectorFileWriter : public QgsFeatureSink
{
SortRecommended = 1 << 1, //!< Use recommended sort order, with extremely commonly used formats listed first
SkipNonSpatialFormats = 1 << 2, //!< Filter out any formats which do not have spatial support (e.g. those which cannot save geometries)
SupportsMultipleLayers = 1 << 3, //!< Filter to only formats which support multiple layers (since QGIS 3.32)
};
Q_DECLARE_FLAGS( VectorFormatOptions, VectorFormatOption )

View File

@ -834,6 +834,17 @@ class TestQgsVectorFileWriter(unittest.TestCase):
formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.SkipNonSpatialFormats)
self.assertFalse('ODS' in [f.driverName for f in formats])
# multilayer formats
formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.SupportsMultipleLayers)
self.assertTrue('DXF' in [f.driverName for f in formats])
self.assertFalse('ESRI Shapefile' in [f.driverName for f in formats])
self.assertTrue('XLSX' in [f.driverName for f in formats])
formats = QgsVectorFileWriter.supportedFiltersAndFormats(QgsVectorFileWriter.SupportsMultipleLayers | QgsVectorFileWriter.SkipNonSpatialFormats)
self.assertTrue('DXF' in [f.driverName for f in formats])
self.assertFalse('ESRI Shapefile' in [f.driverName for f in formats])
self.assertFalse('XLSX' in [f.driverName for f in formats])
def testOgrDriverList(self):
# test with drivers in recommended order
drivers = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.SortRecommended)
@ -860,6 +871,17 @@ class TestQgsVectorFileWriter(unittest.TestCase):
formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.SkipNonSpatialFormats)
self.assertFalse('ODS' in [f.driverName for f in formats])
# multilayer formats
formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.SupportsMultipleLayers)
self.assertTrue('DXF' in [f.driverName for f in formats])
self.assertFalse('ESRI Shapefile' in [f.driverName for f in formats])
self.assertTrue('XLSX' in [f.driverName for f in formats])
formats = QgsVectorFileWriter.ogrDriverList(QgsVectorFileWriter.SupportsMultipleLayers | QgsVectorFileWriter.SkipNonSpatialFormats)
self.assertTrue('DXF' in [f.driverName for f in formats])
self.assertFalse('ESRI Shapefile' in [f.driverName for f in formats])
self.assertFalse('XLSX' in [f.driverName for f in formats])
def testSupportedFormatExtensions(self):
formats = QgsVectorFileWriter.supportedFormatExtensions()
self.assertTrue('gpkg' in formats)