mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[processing] Extend api for retrieving a layer in a compatible format
A few releases ago a bug fix was implemented which forced conversions of multi-layer sources. This was a valid bug fix, but the consequence was that any algorithm using this api with a source file containing multiple layers (e.g. gpkg) performed a complete copy of the target layer to a new file, severely impacting performance. This commit adds new API to retrieve a compatible layer path in the case when an algorithm CAN correctly handle specific target layer names. In this case, the forced copy of the source layer is avoided when using multi-layer inputs like geopackage.
This commit is contained in:
parent
b3f9ce1c26
commit
651c507180
@ -661,6 +661,43 @@ in a temporary location. The function will then return the path to that temporar
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required.
|
||||
|
||||
When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
to use parameterAsCompatibleSourceLayerPathAndLayerName() which may avoid conversion in more situations.
|
||||
%End
|
||||
|
||||
QString parameterAsCompatibleSourceLayerPathAndLayerName( const QVariantMap ¶meters, const QString &name,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = 0, QString *layerName /Out/ = 0 );
|
||||
%Docstring
|
||||
Evaluates the parameter with matching ``name`` to a source vector layer file path and layer name of compatible format.
|
||||
|
||||
If the parameter is evaluated to an existing layer, and that layer is not of the format listed in the
|
||||
``compatibleFormats`` argument, then the layer will first be exported to a compatible format
|
||||
in a temporary location. The function will then return the path to that temporary file.
|
||||
|
||||
``compatibleFormats`` should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
|
||||
This method should be preferred over parameterAsCompatibleSourceLayerPath() when an algorithm is able
|
||||
to correctly handle files with multiple layers. Unlike parameterAsCompatibleSourceLayerPath(), it will not force
|
||||
a conversion in this case and will return the target layer name in the ``layerName`` argument.
|
||||
|
||||
:param parameters: input parameter value map
|
||||
:param name: name of target parameter
|
||||
:param context: processing context
|
||||
:param compatibleFormats: a list of lowercase file extensions compatible with the algorithm
|
||||
:param preferredFormat: preferred format extension to use if conversion if required
|
||||
:param feedback: feedback object
|
||||
|
||||
:return: - path to source layer, or nearly converted compatible layer
|
||||
- layerName: will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
|
||||
|
||||
.. seealso:: :py:func:`parameterAsCompatibleSourceLayerPath`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
QgsMapLayer *parameterAsLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const;
|
||||
|
@ -732,6 +732,43 @@ in a temporary location. The function will then return the path to that temporar
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
|
||||
When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
to use parameterAsCompatibleSourceLayerPathAndLayerName() which may avoid conversion in more situations.
|
||||
%End
|
||||
|
||||
static QString parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = 0, QString *layerName /Out/ = 0 );
|
||||
%Docstring
|
||||
Evaluates the parameter with matching ``definition`` to a source vector layer file path and layer name of compatible format.
|
||||
|
||||
If the parameter is evaluated to an existing layer, and that layer is not of the format listed in the
|
||||
``compatibleFormats`` argument, then the layer will first be exported to a compatible format
|
||||
in a temporary location. The function will then return the path to that temporary file.
|
||||
|
||||
``compatibleFormats`` should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
|
||||
This method should be preferred over parameterAsCompatibleSourceLayerPath() when an algorithm is able
|
||||
to correctly handle files with multiple layers. Unlike parameterAsCompatibleSourceLayerPath(), it will not force
|
||||
a conversion in this case and will return the target layer name in the ``layerName`` argument.
|
||||
|
||||
:param definition: associated parameter definition
|
||||
:param parameters: input parameter value map
|
||||
:param context: processing context
|
||||
:param compatibleFormats: a list of lowercase file extensions compatible with the algorithm
|
||||
:param preferredFormat: preferred format extension to use if conversion if required
|
||||
:param feedback: feedback object
|
||||
|
||||
:return: - path to source layer, or nearly converted compatible layer
|
||||
- layerName: will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
|
||||
|
||||
.. seealso:: :py:func:`parameterAsCompatibleSourceLayerPath`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
static QgsMapLayer *parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context );
|
||||
|
@ -232,7 +232,7 @@ a specified ``algorithm``.
|
||||
QgsProcessingContext &context,
|
||||
QgsProcessingFeedback *feedback );
|
||||
%Docstring
|
||||
Converts a source vector ``layer`` to a file path to a vector layer of compatible format.
|
||||
Converts a source vector ``layer`` to a file path of a vector layer of compatible format.
|
||||
|
||||
If the specified ``layer`` is not of the format listed in the
|
||||
``compatibleFormats`` argument, then the layer will first be exported to a compatible format
|
||||
@ -242,6 +242,52 @@ in a temporary location using ``baseName``. The function will then return the pa
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required. This defaults to shapefiles.
|
||||
|
||||
When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
to use convertToCompatibleFormatAndLayerName() which may avoid conversion in more situations.
|
||||
|
||||
.. seealso:: :py:func:`convertToCompatibleFormatAndLayerName`
|
||||
%End
|
||||
|
||||
static QString convertToCompatibleFormatAndLayerName( const QgsVectorLayer *layer,
|
||||
bool selectedFeaturesOnly,
|
||||
const QString &baseName,
|
||||
const QStringList &compatibleFormats,
|
||||
const QString &preferredFormat,
|
||||
QgsProcessingContext &context,
|
||||
QgsProcessingFeedback *feedback,
|
||||
QString &layerName /Out/ );
|
||||
%Docstring
|
||||
Converts a source vector ``layer`` to a file path and layer name of a vector layer of compatible format.
|
||||
|
||||
If the specified ``layer`` is not of the format listed in the
|
||||
``compatibleFormats`` argument, then the layer will first be exported to a compatible format
|
||||
in a temporary location using ``baseName``. The function will then return the path to that temporary file.
|
||||
|
||||
``compatibleFormats`` should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
|
||||
The ``preferredFormat`` argument is used to specify to desired file extension to use when a temporary
|
||||
layer export is required. This defaults to shapefiles.
|
||||
|
||||
This method should be preferred over convertToCompatibleFormat() when an algorithm is able
|
||||
to correctly handle files with multiple layers. Unlike convertToCompatibleFormat(), it will not force
|
||||
a conversion in this case and will return the target layer name in the ``layerName`` argument.
|
||||
|
||||
:param layer: source layer to convert (if required)
|
||||
:param selectedFeaturesOnly: ``True`` if only selected features from the layer should be used
|
||||
:param baseName: base file name for converted layer, if required
|
||||
:param compatibleFormats: a list of lowercase file extensions compatible with the algorithm
|
||||
:param preferredFormat: preferred format extension to use if conversion if required
|
||||
:param context: processing context
|
||||
:param feedback: feedback object
|
||||
|
||||
:return: - path to source layer, or nearly converted compatible layer
|
||||
- layerName: will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
|
||||
|
||||
.. seealso:: :py:func:`convertToCompatibleFormat`
|
||||
|
||||
.. versionadded:: 3.10
|
||||
%End
|
||||
|
||||
static QgsFields combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix = QString() );
|
||||
|
@ -612,6 +612,11 @@ QString QgsProcessingAlgorithm::parameterAsCompatibleSourceLayerPath( const QVar
|
||||
return QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( parameterDefinition( name ), parameters, context, compatibleFormats, preferredFormat, feedback );
|
||||
}
|
||||
|
||||
QString QgsProcessingAlgorithm::parameterAsCompatibleSourceLayerPathAndLayerName( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
|
||||
{
|
||||
return QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( parameterDefinition( name ), parameters, context, compatibleFormats, preferredFormat, feedback, layerName );
|
||||
}
|
||||
|
||||
QgsMapLayer *QgsProcessingAlgorithm::parameterAsLayer( const QVariantMap ¶meters, const QString &name, QgsProcessingContext &context ) const
|
||||
{
|
||||
return QgsProcessingParameters::parameterAsLayer( parameterDefinition( name ), parameters, context );
|
||||
|
@ -653,10 +653,45 @@ class CORE_EXPORT QgsProcessingAlgorithm
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required.
|
||||
*
|
||||
* When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
* to use parameterAsCompatibleSourceLayerPathAndLayerName() which may avoid conversion in more situations.
|
||||
*/
|
||||
QString parameterAsCompatibleSourceLayerPath( const QVariantMap ¶meters, const QString &name,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = nullptr );
|
||||
|
||||
/**
|
||||
* Evaluates the parameter with matching \a name to a source vector layer file path and layer name of compatible format.
|
||||
*
|
||||
* If the parameter is evaluated to an existing layer, and that layer is not of the format listed in the
|
||||
* \a compatibleFormats argument, then the layer will first be exported to a compatible format
|
||||
* in a temporary location. The function will then return the path to that temporary file.
|
||||
*
|
||||
* \a compatibleFormats should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
*
|
||||
* This method should be preferred over parameterAsCompatibleSourceLayerPath() when an algorithm is able
|
||||
* to correctly handle files with multiple layers. Unlike parameterAsCompatibleSourceLayerPath(), it will not force
|
||||
* a conversion in this case and will return the target layer name in the \a layerName argument.
|
||||
*
|
||||
* \param parameters input parameter value map
|
||||
* \param name name of target parameter
|
||||
* \param context processing context
|
||||
* \param compatibleFormats a list of lowercase file extensions compatible with the algorithm
|
||||
* \param preferredFormat preferred format extension to use if conversion if required
|
||||
* \param feedback feedback object
|
||||
* \param layerName will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
*
|
||||
* \returns path to source layer, or nearly converted compatible layer
|
||||
*
|
||||
* \see parameterAsCompatibleSourceLayerPath()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
QString parameterAsCompatibleSourceLayerPathAndLayerName( const QVariantMap ¶meters, const QString &name,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = nullptr, QString *layerName SIP_OUT = nullptr );
|
||||
|
||||
/**
|
||||
* Evaluates the parameter with matching \a name to a map layer.
|
||||
*
|
||||
|
@ -480,7 +480,7 @@ QgsProcessingFeatureSource *QgsProcessingParameters::parameterAsSource( const Qg
|
||||
return QgsProcessingUtils::variantToSource( value, context, definition->defaultValue() );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
|
||||
QString parameterAsCompatibleSourceLayerPathInternal( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
|
||||
{
|
||||
if ( !definition )
|
||||
return QString();
|
||||
@ -544,8 +544,29 @@ QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const Qgs
|
||||
if ( !vl )
|
||||
return QString();
|
||||
|
||||
return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
|
||||
compatibleFormats, preferredFormat, context, feedback );
|
||||
if ( layerName )
|
||||
return QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vl, selectedFeaturesOnly, definition->name(),
|
||||
compatibleFormats, preferredFormat, context, feedback, *layerName );
|
||||
else
|
||||
return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
|
||||
compatibleFormats, preferredFormat, context, feedback );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, nullptr );
|
||||
}
|
||||
|
||||
QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback, QString *layerName )
|
||||
{
|
||||
QString *destLayer = layerName;
|
||||
QString tmp;
|
||||
if ( destLayer )
|
||||
destLayer->clear();
|
||||
else
|
||||
destLayer = &tmp;
|
||||
|
||||
return parameterAsCompatibleSourceLayerPathInternal( definition, parameters, context, compatibleFormats, preferredFormat, feedback, destLayer );
|
||||
}
|
||||
|
||||
|
||||
|
@ -793,10 +793,45 @@ class CORE_EXPORT QgsProcessingParameters
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
*
|
||||
* When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
* to use parameterAsCompatibleSourceLayerPathAndLayerName() which may avoid conversion in more situations.
|
||||
*/
|
||||
static QString parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = nullptr );
|
||||
|
||||
/**
|
||||
* Evaluates the parameter with matching \a definition to a source vector layer file path and layer name of compatible format.
|
||||
*
|
||||
* If the parameter is evaluated to an existing layer, and that layer is not of the format listed in the
|
||||
* \a compatibleFormats argument, then the layer will first be exported to a compatible format
|
||||
* in a temporary location. The function will then return the path to that temporary file.
|
||||
*
|
||||
* \a compatibleFormats should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required. This defaults to shapefiles, because shapefiles are the future (don't believe the geopackage hype!).
|
||||
*
|
||||
* This method should be preferred over parameterAsCompatibleSourceLayerPath() when an algorithm is able
|
||||
* to correctly handle files with multiple layers. Unlike parameterAsCompatibleSourceLayerPath(), it will not force
|
||||
* a conversion in this case and will return the target layer name in the \a layerName argument.
|
||||
*
|
||||
* \param definition associated parameter definition
|
||||
* \param parameters input parameter value map
|
||||
* \param context processing context
|
||||
* \param compatibleFormats a list of lowercase file extensions compatible with the algorithm
|
||||
* \param preferredFormat preferred format extension to use if conversion if required
|
||||
* \param feedback feedback object
|
||||
* \param layerName will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
*
|
||||
* \returns path to source layer, or nearly converted compatible layer
|
||||
*
|
||||
* \see parameterAsCompatibleSourceLayerPath()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
static QString parameterAsCompatibleSourceLayerPathAndLayerName( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters,
|
||||
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = nullptr, QString *layerName SIP_OUT = nullptr );
|
||||
|
||||
/**
|
||||
* Evaluates the parameter with matching \a definition to a map layer.
|
||||
*
|
||||
|
@ -779,7 +779,7 @@ QString QgsProcessingUtils::formatHelpMapAsHtml( const QVariantMap &map, const Q
|
||||
return s;
|
||||
}
|
||||
|
||||
QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
QString convertToCompatibleFormatInternal( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString *layerName )
|
||||
{
|
||||
bool requiresTranslation = false;
|
||||
|
||||
@ -813,8 +813,17 @@ QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl,
|
||||
|
||||
// if the layer name doesn't match the filename, we need to convert the layer. This method can only return
|
||||
// a filename, and cannot handle layernames as well as file paths
|
||||
const QString layerName = parts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
requiresTranslation = requiresTranslation || ( !layerName.isEmpty() && layerName != fi.baseName() );
|
||||
const QString srcLayerName = parts.value( QStringLiteral( "layerName" ) ).toString();
|
||||
if ( layerName )
|
||||
{
|
||||
// differing layer names are acceptable
|
||||
*layerName = srcLayerName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// differing layer names are NOT acceptable
|
||||
requiresTranslation = requiresTranslation || ( !srcLayerName.isEmpty() && srcLayerName != fi.baseName() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -849,6 +858,17 @@ QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl,
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||
{
|
||||
return convertToCompatibleFormatInternal( vl, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, nullptr );
|
||||
}
|
||||
|
||||
QString QgsProcessingUtils::convertToCompatibleFormatAndLayerName( const QgsVectorLayer *layer, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback, QString &layerName )
|
||||
{
|
||||
layerName.clear();
|
||||
return convertToCompatibleFormatInternal( layer, selectedFeaturesOnly, baseName, compatibleFormats, preferredFormat, context, feedback, &layerName );
|
||||
}
|
||||
|
||||
QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB, const QString &fieldsBPrefix )
|
||||
{
|
||||
QgsFields outFields = fieldsA;
|
||||
|
@ -258,7 +258,7 @@ class CORE_EXPORT QgsProcessingUtils
|
||||
static QString formatHelpMapAsHtml( const QVariantMap &map, const QgsProcessingAlgorithm *algorithm );
|
||||
|
||||
/**
|
||||
* Converts a source vector \a layer to a file path to a vector layer of compatible format.
|
||||
* Converts a source vector \a layer to a file path of a vector layer of compatible format.
|
||||
*
|
||||
* If the specified \a layer is not of the format listed in the
|
||||
* \a compatibleFormats argument, then the layer will first be exported to a compatible format
|
||||
@ -268,6 +268,11 @@ class CORE_EXPORT QgsProcessingUtils
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required. This defaults to shapefiles.
|
||||
*
|
||||
* When an algorithm is capable of handling multi-layer input files (such as Geopackage), it is preferable
|
||||
* to use convertToCompatibleFormatAndLayerName() which may avoid conversion in more situations.
|
||||
*
|
||||
* \see convertToCompatibleFormatAndLayerName()
|
||||
*/
|
||||
static QString convertToCompatibleFormat( const QgsVectorLayer *layer,
|
||||
bool selectedFeaturesOnly,
|
||||
@ -277,6 +282,45 @@ class CORE_EXPORT QgsProcessingUtils
|
||||
QgsProcessingContext &context,
|
||||
QgsProcessingFeedback *feedback );
|
||||
|
||||
/**
|
||||
* Converts a source vector \a layer to a file path and layer name of a vector layer of compatible format.
|
||||
*
|
||||
* If the specified \a layer is not of the format listed in the
|
||||
* \a compatibleFormats argument, then the layer will first be exported to a compatible format
|
||||
* in a temporary location using \a baseName. The function will then return the path to that temporary file.
|
||||
*
|
||||
* \a compatibleFormats should consist entirely of lowercase file extensions, e.g. 'shp'.
|
||||
*
|
||||
* The \a preferredFormat argument is used to specify to desired file extension to use when a temporary
|
||||
* layer export is required. This defaults to shapefiles.
|
||||
*
|
||||
* This method should be preferred over convertToCompatibleFormat() when an algorithm is able
|
||||
* to correctly handle files with multiple layers. Unlike convertToCompatibleFormat(), it will not force
|
||||
* a conversion in this case and will return the target layer name in the \a layerName argument.
|
||||
*
|
||||
* \param layer source layer to convert (if required)
|
||||
* \param selectedFeaturesOnly TRUE if only selected features from the layer should be used
|
||||
* \param baseName base file name for converted layer, if required
|
||||
* \param compatibleFormats a list of lowercase file extensions compatible with the algorithm
|
||||
* \param preferredFormat preferred format extension to use if conversion if required
|
||||
* \param context processing context
|
||||
* \param feedback feedback object
|
||||
* \param layerName will be set to the target layer name for multi-layer sources (e.g. Geopackage)
|
||||
*
|
||||
* \returns path to source layer, or nearly converted compatible layer
|
||||
*
|
||||
* \see convertToCompatibleFormat()
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
static QString convertToCompatibleFormatAndLayerName( const QgsVectorLayer *layer,
|
||||
bool selectedFeaturesOnly,
|
||||
const QString &baseName,
|
||||
const QStringList &compatibleFormats,
|
||||
const QString &preferredFormat,
|
||||
QgsProcessingContext &context,
|
||||
QgsProcessingFeedback *feedback,
|
||||
QString &layerName SIP_OUT );
|
||||
|
||||
/**
|
||||
* Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
|
||||
*
|
||||
|
@ -8184,6 +8184,12 @@ void TestQgsProcessing::convertCompatible()
|
||||
// layer should be returned unchanged - underlying source is compatible
|
||||
QCOMPARE( out, layer->source() );
|
||||
|
||||
QString layerName;
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
// layer should be returned unchanged - underlying source is compatible
|
||||
QCOMPARE( out, layer->source() );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// path with layer suffix
|
||||
QString vectorWithLayer = testDataDir + "points.shp|layername=points";
|
||||
QgsVectorLayer *layer2 = new QgsVectorLayer( vectorWithLayer, "vl" );
|
||||
@ -8191,6 +8197,9 @@ void TestQgsProcessing::convertCompatible()
|
||||
out = QgsProcessingUtils::convertToCompatibleFormat( layer2, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback );
|
||||
// layer should be returned unchanged - underlying source is compatible
|
||||
QCOMPARE( out, vector );
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer2, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QCOMPARE( out, vector );
|
||||
QCOMPARE( layerName, QStringLiteral( "points" ) );
|
||||
|
||||
// don't include shp as compatible type
|
||||
out = QgsProcessingUtils::convertToCompatibleFormat( layer, false, QStringLiteral( "test" ), QStringList() << "tab", QString( "tab" ), context, &feedback );
|
||||
@ -8203,6 +8212,12 @@ void TestQgsProcessing::convertCompatible()
|
||||
QCOMPARE( layer->featureCount(), t->featureCount() );
|
||||
QCOMPARE( layer->crs(), t->crs() );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer, false, QStringLiteral( "test2" ), QStringList() << "tab", QString( "tab" ), context, &feedback, layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// use a selection - this will require translation
|
||||
QgsFeatureIds ids;
|
||||
QgsFeature f;
|
||||
@ -8220,6 +8235,14 @@ void TestQgsProcessing::convertCompatible()
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer, true, QStringLiteral( "test" ), QStringList() << "tab", QString( "tab" ), context, &feedback, layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// using a selection but existing format - will still require translation
|
||||
out = QgsProcessingUtils::convertToCompatibleFormat( layer, true, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback );
|
||||
QVERIFY( out != layer->source() );
|
||||
@ -8228,6 +8251,14 @@ void TestQgsProcessing::convertCompatible()
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer, true, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// using a feature filter -- this will require translation
|
||||
layer->setSubsetString( "1 or 2" );
|
||||
out = QgsProcessingUtils::convertToCompatibleFormat( layer, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback );
|
||||
@ -8236,6 +8267,14 @@ void TestQgsProcessing::convertCompatible()
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), layer->featureCount() );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( layer, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), layer->featureCount() );
|
||||
QCOMPARE( layerName, QString() );
|
||||
layer->setSubsetString( QString() );
|
||||
|
||||
// using GDAL's virtual I/O (/vsizip/, etc.)
|
||||
@ -8250,6 +8289,15 @@ void TestQgsProcessing::convertCompatible()
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), layer->featureCount() );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( vsiLayer, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( !out.contains( "/vsizip" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), layer->featureCount() );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// non-OGR source -- must be translated, regardless of extension. (e.g. delimited text provider handles CSV very different to OGR!)
|
||||
std::unique_ptr< QgsVectorLayer > memLayer = qgis::make_unique< QgsVectorLayer> ( "Point", "v1", "memory" );
|
||||
for ( int i = 1; i < 6; ++i )
|
||||
@ -8265,6 +8313,14 @@ void TestQgsProcessing::convertCompatible()
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), memLayer->featureCount() );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( memLayer.get(), false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QVERIFY( out != memLayer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), memLayer->featureCount() );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
//delimited text -- must be translated, regardless of extension. (delimited text provider handles CSV very different to OGR!)
|
||||
QString csvPath = "file://" + testDataDir + "delimitedtext/testpt.csv?type=csv&useHeader=No&detectTypes=yes&xyDms=yes&geomType=none&subsetIndex=no&watchFile=no";
|
||||
std::unique_ptr< QgsVectorLayer > csvLayer = qgis::make_unique< QgsVectorLayer >( csvPath, "vl", "delimitedtext" );
|
||||
@ -8276,6 +8332,14 @@ void TestQgsProcessing::convertCompatible()
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), csvLayer->featureCount() );
|
||||
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( csvLayer.get(), false, QStringLiteral( "test" ), QStringList() << "csv", QString( "csv" ), context, &feedback, layerName );
|
||||
QVERIFY( out != csvLayer->source() );
|
||||
QVERIFY( out.endsWith( ".csv" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
t = qgis::make_unique< QgsVectorLayer >( out, "vl2" );
|
||||
QCOMPARE( t->featureCount(), csvLayer->featureCount() );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// geopackage with layer
|
||||
QString gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_gpkg";
|
||||
std::unique_ptr< QgsVectorLayer > gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
@ -8290,29 +8354,59 @@ void TestQgsProcessing::convertCompatible()
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_gpkg";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( gpkgLayer.get(), false, QStringLiteral( "test" ), QStringList() << "gpkg" << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
// layer SHOULD NOT be translated -- in this case we know that the external tool can handle specifying the correct layer
|
||||
QCOMPARE( out, testDataDir + QStringLiteral( "points_gpkg.gpkg" ) );
|
||||
QCOMPARE( layerName, QStringLiteral( "points_gpkg" ) );
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_small";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
out = QgsProcessingUtils::convertToCompatibleFormatAndLayerName( gpkgLayer.get(), false, QStringLiteral( "test" ), QStringList() << "gpkg" << "shp", QString( "shp" ), context, &feedback, layerName );
|
||||
QCOMPARE( out, testDataDir + QStringLiteral( "points_gpkg.gpkg" ) );
|
||||
QCOMPARE( layerName, QStringLiteral( "points_small" ) );
|
||||
|
||||
// also test evaluating parameter to compatible format
|
||||
std::unique_ptr< QgsProcessingParameterDefinition > def( new QgsProcessingParameterFeatureSource( QStringLiteral( "source" ) ) );
|
||||
QVariantMap params;
|
||||
params.insert( QStringLiteral( "source" ), QgsProcessingFeatureSourceDefinition( layer->id(), false ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// incompatible format, will be converted
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "tab", QString( "tab" ), &feedback );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "tab", QString( "tab" ), &feedback, &layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// layer as input
|
||||
params.insert( QStringLiteral( "source" ), QVariant::fromValue( layer ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// incompatible format, will be converted
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "tab", QString( "tab" ), &feedback );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "tab", QString( "tab" ), &feedback, &layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".tab" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// selected only, will force export
|
||||
params.insert( QStringLiteral( "source" ), QgsProcessingFeatureSourceDefinition( layer->id(), true ) );
|
||||
@ -8320,17 +8414,60 @@ void TestQgsProcessing::convertCompatible()
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QVERIFY( out != layer->source() );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// vector layer as default
|
||||
def.reset( new QgsProcessingParameterFeatureSource( QStringLiteral( "source" ), QString(), QList<int>(), QVariant::fromValue( layer ) ) );
|
||||
params.remove( QStringLiteral( "source" ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
QCOMPARE( layerName, QString() );
|
||||
|
||||
// geopackage with layer
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_gpkg";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
params.insert( QStringLiteral( "source" ), QVariant::fromValue( gpkgLayer.get() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "gpkg" << "shp", QString( "shp" ), &feedback );
|
||||
// layer must be translated -- we do not know if external tool can handle picking the correct layer automatically
|
||||
QCOMPARE( out, testDataDir + QStringLiteral( "points_gpkg.gpkg" ) );
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_small";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
params.insert( QStringLiteral( "source" ), QVariant::fromValue( gpkgLayer.get() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "gpkg" << "shp", QString( "shp" ), &feedback );
|
||||
QVERIFY( out.endsWith( ".shp" ) );
|
||||
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_gpkg";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
params.insert( QStringLiteral( "source" ), QVariant::fromValue( gpkgLayer.get() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "gpkg" << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
// layer SHOULD NOT be translated -- in this case we know that the external tool can handle specifying the correct layer
|
||||
QCOMPARE( out, testDataDir + QStringLiteral( "points_gpkg.gpkg" ) );
|
||||
QCOMPARE( layerName, QStringLiteral( "points_gpkg" ) );
|
||||
gpkgPath = testDataDir + "points_gpkg.gpkg|layername=points_small";
|
||||
gpkgLayer = qgis::make_unique< QgsVectorLayer >( gpkgPath, "vl" );
|
||||
QVERIFY( gpkgLayer->isValid() );
|
||||
params.insert( QStringLiteral( "source" ), QVariant::fromValue( gpkgLayer.get() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "gpkg" << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QCOMPARE( out, testDataDir + QStringLiteral( "points_gpkg.gpkg" ) );
|
||||
QCOMPARE( layerName, QStringLiteral( "points_small" ) );
|
||||
|
||||
// output layer as input - e.g. from a previous model child
|
||||
params.insert( QStringLiteral( "source" ), QgsProcessingOutputLayerDefinition( layer->id() ) );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPathAndLayerName( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback, &layerName );
|
||||
QCOMPARE( out, testDataDir + "points.shp" );
|
||||
QCOMPARE( layerName, QString() );
|
||||
}
|
||||
|
||||
void TestQgsProcessing::create()
|
||||
|
Loading…
x
Reference in New Issue
Block a user