Add flag to babel command generation methods to control whether

paths should be quoted
This commit is contained in:
Nyall Dawson 2021-08-02 10:39:06 +10:00
parent 5df3be570d
commit 47f7612004
10 changed files with 110 additions and 44 deletions

View File

@ -508,6 +508,11 @@ Qgis.BabelFormatCapability.__doc__ = 'Babel GPS format capabilities.\n\n.. versi
# --
Qgis.BabelFormatCapability.baseClass = Qgis
# monkey patching scoped based enum
Qgis.BabelCommandFlag.QuoteFilePaths.__doc__ = "File paths should be enclosed in quotations and escaped"
Qgis.BabelCommandFlag.__doc__ = 'Babel command flags, which control how commands and arguments\nare generated for executing GPSBabel processes.\n\n.. versionadded:: 3.22\n\n' + '* ``QuoteFilePaths``: ' + Qgis.BabelCommandFlag.QuoteFilePaths.__doc__
# --
Qgis.BabelCommandFlag.baseClass = Qgis
# monkey patching scoped based enum
Qgis.GpsFeatureType.Waypoint.__doc__ = "Waypoint"
Qgis.GpsFeatureType.Route.__doc__ = "Route"
Qgis.GpsFeatureType.Track.__doc__ = "Track"

View File

@ -37,7 +37,8 @@ Returns the format's capabilities.
virtual QStringList importCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
%Docstring
Generates a command for importing data into a GPS format using babel.
@ -45,6 +46,7 @@ Generates a command for importing data into a GPS format using babel.
:param featureType: type of GPS feature to import
:param input: input data path
:param output: output path
:param flags: optional flags to control how babel command is generated
Returns an empty list if the format does not support imports (see :py:func:`~QgsAbstractBabelFormat.capabilities`).
%End
@ -52,7 +54,8 @@ Returns an empty list if the format does not support imports (see :py:func:`~Qgs
virtual QStringList exportCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
%Docstring
Generates a command for exporting GPS data into a different format using babel.
@ -60,6 +63,7 @@ Generates a command for exporting GPS data into a different format using babel.
:param featureType: type of GPS feature to export
:param input: input data path
:param output: output path
:param flags: optional flags to control how babel command is generated
Returns an empty list if the format does not support exports (see :py:func:`~QgsAbstractBabelFormat.capabilities`).
%End
@ -122,7 +126,8 @@ Returns the list of known extensions for the format, e.g. "csv", "txt".
virtual QStringList importCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
};
/************************************************************************

View File

@ -45,10 +45,10 @@ Constructor for QgsBabelGpsDeviceFormat.
:param trackUploadCommand: command for uploading tracks to device
%End
virtual QStringList importCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out ) const;
virtual QStringList exportCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out ) const;
virtual QStringList importCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
virtual QStringList exportCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
};

View File

@ -371,6 +371,13 @@ The development version
typedef QFlags<Qgis::BabelFormatCapability> BabelFormatCapabilities;
enum class BabelCommandFlag
{
QuoteFilePaths,
};
typedef QFlags<Qgis::BabelCommandFlag> BabelCommandFlags;
enum class GpsFeatureType
{
Waypoint,
@ -457,6 +464,8 @@ QFlags<Qgis::SqlLayerDefinitionCapability> operator|(Qgis::SqlLayerDefinitionCap
QFlags<Qgis::BabelFormatCapability> operator|(Qgis::BabelFormatCapability f1, QFlags<Qgis::BabelFormatCapability> f2);
QFlags<Qgis::BabelCommandFlag> operator|(Qgis::BabelCommandFlag f1, QFlags<Qgis::BabelCommandFlag> f2);

View File

@ -43,12 +43,12 @@ QString QgsAbstractBabelFormat::name() const
return mName;
}
QStringList QgsAbstractBabelFormat::importCommand( const QString &, Qgis::GpsFeatureType, const QString &, const QString & ) const
QStringList QgsAbstractBabelFormat::importCommand( const QString &, Qgis::GpsFeatureType, const QString &, const QString &, Qgis::BabelCommandFlags ) const
{
return QStringList();
}
QStringList QgsAbstractBabelFormat::exportCommand( const QString &, Qgis::GpsFeatureType, const QString &, const QString & ) const
QStringList QgsAbstractBabelFormat::exportCommand( const QString &, Qgis::GpsFeatureType, const QString &, const QString &, Qgis::BabelCommandFlags ) const
{
return QStringList();
}
@ -77,14 +77,16 @@ QgsBabelSimpleImportFormat::QgsBabelSimpleImportFormat( const QString &format, c
QStringList QgsBabelSimpleImportFormat::importCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output )const
const QString &output,
Qgis::BabelCommandFlags flags ) const
{
return { QStringLiteral( "\"%1\"" ).arg( babel ),
return { flags &Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( babel ) : babel,
featureTypeToArgument( featureType ),
QStringLiteral( "-i" ),
name(),
QStringLiteral( "-o" ),
QStringLiteral( "gpx" ),
QStringLiteral( "\"%1\"" ).arg( input ),
QStringLiteral( "\"%1\"" ).arg( output ) };
flags &Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( input ) : input,
flags &Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( output ) : output
};
}

View File

@ -53,13 +53,15 @@ class CORE_EXPORT QgsAbstractBabelFormat
* \param featureType type of GPS feature to import
* \param input input data path
* \param output output path
* \param flags optional flags to control how babel command is generated
*
* Returns an empty list if the format does not support imports (see capabilities()).
*/
virtual QStringList importCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
/**
* Generates a command for exporting GPS data into a different format using babel.
@ -68,13 +70,15 @@ class CORE_EXPORT QgsAbstractBabelFormat
* \param featureType type of GPS feature to export
* \param input input data path
* \param output output path
* \param flags optional flags to control how babel command is generated
*
* Returns an empty list if the format does not support exports (see capabilities()).
*/
virtual QStringList exportCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const;
protected:
@ -135,7 +139,8 @@ class CORE_EXPORT QgsBabelSimpleImportFormat : public QgsAbstractBabelFormat
QStringList importCommand( const QString &babel,
Qgis::GpsFeatureType featureType,
const QString &input,
const QString &output ) const override;
const QString &output,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const override;
private:
QString mDescription;
QStringList mExtensions;

View File

@ -56,7 +56,7 @@ QgsBabelGpsDeviceFormat::QgsBabelGpsDeviceFormat( const QString &waypointDownloa
QStringList QgsBabelGpsDeviceFormat::importCommand( const QString &babel,
Qgis::GpsFeatureType type,
const QString &in,
const QString &out ) const
const QString &out, Qgis::BabelCommandFlags flags ) const
{
QStringList original;
@ -78,13 +78,13 @@ QStringList QgsBabelGpsDeviceFormat::importCommand( const QString &babel,
for ( const QString &iter : std::as_const( original ) )
{
if ( iter == QLatin1String( "%babel" ) )
copy.append( babel );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( babel ) : babel );
else if ( iter == QLatin1String( "%type" ) )
copy.append( featureTypeToArgument( type ) );
else if ( iter == QLatin1String( "%in" ) )
copy.append( QStringLiteral( "\"%1\"" ).arg( in ) );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( in ) : in );
else if ( iter == QLatin1String( "%out" ) )
copy.append( QStringLiteral( "\"%1\"" ).arg( out ) );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( out ) : out );
else
copy.append( iter );
}
@ -94,7 +94,7 @@ QStringList QgsBabelGpsDeviceFormat::importCommand( const QString &babel,
QStringList QgsBabelGpsDeviceFormat::exportCommand( const QString &babel,
Qgis::GpsFeatureType type,
const QString &in,
const QString &out ) const
const QString &out, Qgis::BabelCommandFlags flags ) const
{
QStringList original;
switch ( type )
@ -115,13 +115,13 @@ QStringList QgsBabelGpsDeviceFormat::exportCommand( const QString &babel,
for ( const QString &iter : std::as_const( original ) )
{
if ( iter == QLatin1String( "%babel" ) )
copy.append( babel );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( babel ) : babel );
else if ( iter == QLatin1String( "%type" ) )
copy.append( featureTypeToArgument( type ) );
else if ( iter == QLatin1String( "%in" ) )
copy.append( QStringLiteral( "\"%1\"" ).arg( in ) );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( in ) : in );
else if ( iter == QLatin1String( "%out" ) )
copy.append( QStringLiteral( "\"%1\"" ).arg( out ) );
copy.append( flags & Qgis::BabelCommandFlag::QuoteFilePaths ? QStringLiteral( "\"%1\"" ).arg( out ) : out );
else
copy.append( iter );
}

View File

@ -56,8 +56,10 @@ class CORE_EXPORT QgsBabelGpsDeviceFormat : public QgsAbstractBabelFormat
const QString &trackDownloadCommand,
const QString &trackUploadCommand );
QStringList importCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out ) const override;
QStringList exportCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out ) const override;
QStringList importCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const override;
QStringList exportCommand( const QString &babel, Qgis::GpsFeatureType type, const QString &in, const QString &out,
Qgis::BabelCommandFlags flags = Qgis::BabelCommandFlags() ) const override;
private:

View File

@ -563,6 +563,19 @@ class CORE_EXPORT Qgis
Q_DECLARE_FLAGS( BabelFormatCapabilities, BabelFormatCapability )
Q_ENUM( BabelFormatCapability )
/**
* Babel command flags, which control how commands and arguments
* are generated for executing GPSBabel processes.
*
* \since QGIS 3.22
*/
enum class BabelCommandFlag : int
{
QuoteFilePaths = 1 << 0, //!< File paths should be enclosed in quotations and escaped
};
Q_DECLARE_FLAGS( BabelCommandFlags, BabelCommandFlag )
Q_ENUM( BabelCommandFlag )
/**
* GPS feature types.
*
@ -696,6 +709,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::BrowserItemCapabilities )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SublayerQueryFlags )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::SqlLayerDefinitionCapabilities )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::BabelFormatCapabilities )
Q_DECLARE_OPERATORS_FOR_FLAGS( Qgis::BabelCommandFlags )
// hack to workaround warnings when casting void pointers
// retrieved from QLibrary::resolve to function pointers.

View File

@ -52,26 +52,38 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'),
['"babel.exe"',
['babel.exe',
'-w',
'-i',
'shapefile',
'-o',
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'),
['"babel.exe"',
['babel.exe',
'-t',
'-i',
'shapefile',
'-o',
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
'-r',
'-i',
'shapefile',
'-o',
'gpx',
'c:/test/test.shp',
'c:/test/test.gpx'])
# with quoted paths
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx', Qgis.BabelCommandFlag.QuoteFilePaths),
['"babel.exe"',
'-r',
'-i',
@ -80,6 +92,7 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
# export not supported
self.assertEqual(
f.exportCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'), [])
@ -101,7 +114,6 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
# self.assertEqual(f.capabilities(), Qgis.BabelFormatCapabilities(
# Qgis.BabelFormatCapability.Waypoints | Qgis.BabelFormatCapability.Import))
# TODO -- babel command should possibly be quoted (or NOT in QgsBabelSimpleImportFormat)
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
@ -110,8 +122,8 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'garmin',
'-o',
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
@ -120,8 +132,8 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'garmin',
'-o',
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.importCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
@ -130,8 +142,8 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'garmin',
'-o',
'gpx',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.exportCommand('babel.exe', Qgis.GpsFeatureType.Waypoint, 'c:/test/test.shp', 'c:/test/test.gpx'),
@ -141,8 +153,8 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'gpx',
'-o',
'garmin',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.exportCommand('babel.exe', Qgis.GpsFeatureType.Track, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
@ -151,11 +163,23 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
'gpx',
'-o',
'garmin',
'"c:/test/test.shp"',
'"c:/test/test.gpx"'])
'c:/test/test.shp',
'c:/test/test.gpx'])
self.assertEqual(
f.exportCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx'),
['babel.exe',
'-r',
'-i',
'gpx',
'-o',
'garmin',
'c:/test/test.shp',
'c:/test/test.gpx'])
# with quoted paths
self.assertEqual(
f.exportCommand('babel.exe', Qgis.GpsFeatureType.Route, 'c:/test/test.shp', 'c:/test/test.gpx', Qgis.BabelCommandFlag.QuoteFilePaths),
['"babel.exe"',
'-r',
'-i',
'gpx',
@ -194,7 +218,7 @@ class TestQgsBabelGpsFormat(unittest.TestCase):
self.assertEqual(registry.deviceNames(), ['Garmin serial'])
self.assertIsNotNone(registry.deviceFormat('Garmin serial'))
self.assertEqual(registry.deviceFormat('Garmin serial').importCommand('bb', Qgis.GpsFeatureType.Waypoint, 'in_file.shp', 'out_file.gpx'),
['bb', '-w', '-i', 'garmin', '-o', 'gpx', '"in_file.shp"', '"out_file.gpx"'])
['bb', '-w', '-i', 'garmin', '-o', 'gpx', 'in_file.shp', 'out_file.gpx'])
if __name__ == '__main__':