mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -04:00
Add method to evaluate parameters to compatible vector layers
of a specified type
This commit is contained in:
parent
f8e37aa7cb
commit
9e184feaed
@ -472,6 +472,22 @@ class QgsProcessingParameters
|
|||||||
:rtype: QgsProcessingFeatureSource
|
:rtype: QgsProcessingFeatureSource
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
static QString parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters,
|
||||||
|
QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat = QString( "shp" ), QgsProcessingFeedback *feedback = 0 );
|
||||||
|
%Docstring
|
||||||
|
Evaluates the parameter with matching ``definition`` to a source vector layer file path 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!).
|
||||||
|
:rtype: str
|
||||||
|
%End
|
||||||
|
|
||||||
static QgsMapLayer *parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context );
|
static QgsMapLayer *parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context );
|
||||||
%Docstring
|
%Docstring
|
||||||
Evaluates the parameter with matching ``definition`` to a map layer.
|
Evaluates the parameter with matching ``definition`` to a map layer.
|
||||||
|
@ -158,6 +158,27 @@ class QgsProcessingUtils
|
|||||||
:rtype: str
|
:rtype: str
|
||||||
%End
|
%End
|
||||||
|
|
||||||
|
static QString convertToCompatibleFormat( const QgsVectorLayer *layer,
|
||||||
|
bool selectedFeaturesOnly,
|
||||||
|
const QString &baseName,
|
||||||
|
const QStringList &compatibleFormats,
|
||||||
|
const QString &preferredFormat,
|
||||||
|
QgsProcessingContext &context,
|
||||||
|
QgsProcessingFeedback *feedback );
|
||||||
|
%Docstring
|
||||||
|
Converts a source vector ``layer`` to a file path to 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.
|
||||||
|
:rtype: str
|
||||||
|
%End
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class QgsProcessingFeatureSource : QgsFeatureSource
|
class QgsProcessingFeatureSource : QgsFeatureSource
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "qgsvectorlayerfeatureiterator.h"
|
#include "qgsvectorlayerfeatureiterator.h"
|
||||||
#include "qgsprocessingoutputs.h"
|
#include "qgsprocessingoutputs.h"
|
||||||
#include "qgssettings.h"
|
#include "qgssettings.h"
|
||||||
|
#include "qgsvectorfilewriter.h"
|
||||||
|
|
||||||
bool QgsProcessingParameters::isDynamic( const QVariantMap ¶meters, const QString &name )
|
bool QgsProcessingParameters::isDynamic( const QVariantMap ¶meters, const QString &name )
|
||||||
{
|
{
|
||||||
@ -327,6 +328,49 @@ QgsProcessingFeatureSource *QgsProcessingParameters::parameterAsSource( const Qg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingFeedback *feedback )
|
||||||
|
{
|
||||||
|
if ( !definition )
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
QVariant val = parameters.value( definition->name() );
|
||||||
|
|
||||||
|
bool selectedFeaturesOnly = false;
|
||||||
|
if ( val.canConvert<QgsProcessingFeatureSourceDefinition>() )
|
||||||
|
{
|
||||||
|
// input is a QgsProcessingFeatureSourceDefinition - get extra properties from it
|
||||||
|
QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast<QgsProcessingFeatureSourceDefinition>( val );
|
||||||
|
selectedFeaturesOnly = fromVar.selectedFeaturesOnly;
|
||||||
|
val = fromVar.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString layerRef;
|
||||||
|
if ( val.canConvert<QgsProperty>() )
|
||||||
|
{
|
||||||
|
layerRef = val.value< QgsProperty >().valueAsString( context.expressionContext(), definition->defaultValue().toString() );
|
||||||
|
}
|
||||||
|
else if ( !val.isValid() || val.toString().isEmpty() )
|
||||||
|
{
|
||||||
|
// fall back to default
|
||||||
|
layerRef = definition->defaultValue().toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
layerRef = val.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( layerRef.isEmpty() )
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context ) );
|
||||||
|
if ( !vl )
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
return QgsProcessingUtils::convertToCompatibleFormat( vl, selectedFeaturesOnly, definition->name(),
|
||||||
|
compatibleFormats, preferredFormat, context, feedback );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QgsMapLayer *QgsProcessingParameters::parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context )
|
QgsMapLayer *QgsProcessingParameters::parameterAsLayer( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context )
|
||||||
{
|
{
|
||||||
if ( !definition )
|
if ( !definition )
|
||||||
|
@ -32,6 +32,7 @@ class QgsFeatureSink;
|
|||||||
class QgsFeatureSource;
|
class QgsFeatureSource;
|
||||||
class QgsProcessingFeatureSource;
|
class QgsProcessingFeatureSource;
|
||||||
class QgsProcessingOutputDefinition;
|
class QgsProcessingOutputDefinition;
|
||||||
|
class QgsProcessingFeedback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \class QgsProcessingFeatureSourceDefinition
|
* \class QgsProcessingFeatureSourceDefinition
|
||||||
@ -508,6 +509,21 @@ class CORE_EXPORT QgsProcessingParameters
|
|||||||
*/
|
*/
|
||||||
static QgsProcessingFeatureSource *parameterAsSource( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ) SIP_FACTORY;
|
static QgsProcessingFeatureSource *parameterAsSource( const QgsProcessingParameterDefinition *definition, const QVariantMap ¶meters, QgsProcessingContext &context ) SIP_FACTORY;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates the parameter with matching \a definition to a source vector layer file path 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!).
|
||||||
|
*/
|
||||||
|
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 map layer.
|
* Evaluates the parameter with matching \a definition to a map layer.
|
||||||
*
|
*
|
||||||
|
@ -461,6 +461,42 @@ QString QgsProcessingUtils::formatHelpMapAsHtml( const QVariantMap &map, const Q
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl, bool selectedFeaturesOnly, const QString &baseName, const QStringList &compatibleFormats, const QString &preferredFormat, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
|
||||||
|
{
|
||||||
|
bool requiresTranslation = selectedFeaturesOnly;
|
||||||
|
if ( !selectedFeaturesOnly )
|
||||||
|
{
|
||||||
|
QFileInfo fi( vl->source() );
|
||||||
|
requiresTranslation = !compatibleFormats.contains( fi.suffix(), Qt::CaseInsensitive );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( requiresTranslation )
|
||||||
|
{
|
||||||
|
QString temp = QgsProcessingUtils::generateTempFilename( baseName + '.' + preferredFormat );
|
||||||
|
|
||||||
|
QgsVectorFileWriter writer( temp, context.defaultEncoding(),
|
||||||
|
vl->fields(), vl->wkbType(), vl->crs(), QgsVectorFileWriter::driverForExtension( preferredFormat ) );
|
||||||
|
QgsFeature f;
|
||||||
|
QgsFeatureIterator it;
|
||||||
|
if ( selectedFeaturesOnly )
|
||||||
|
it = vl->getSelectedFeatures();
|
||||||
|
else
|
||||||
|
it = vl->getFeatures();
|
||||||
|
|
||||||
|
while ( it.nextFeature( f ) )
|
||||||
|
{
|
||||||
|
if ( feedback->isCanceled() )
|
||||||
|
return QString();
|
||||||
|
writer.addFeature( f, QgsFeatureSink::FastInsert );
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return vl->source();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// QgsProcessingFeatureSource
|
// QgsProcessingFeatureSource
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
class QgsProject;
|
class QgsProject;
|
||||||
class QgsProcessingContext;
|
class QgsProcessingContext;
|
||||||
class QgsMapLayerStore;
|
class QgsMapLayerStore;
|
||||||
|
class QgsProcessingFeedback;
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
@ -189,6 +190,26 @@ class CORE_EXPORT QgsProcessingUtils
|
|||||||
*/
|
*/
|
||||||
static QString formatHelpMapAsHtml( const QVariantMap &map, const QgsProcessingAlgorithm *algorithm );
|
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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static QString convertToCompatibleFormat( const QgsVectorLayer *layer,
|
||||||
|
bool selectedFeaturesOnly,
|
||||||
|
const QString &baseName,
|
||||||
|
const QStringList &compatibleFormats,
|
||||||
|
const QString &preferredFormat,
|
||||||
|
QgsProcessingContext &context,
|
||||||
|
QgsProcessingFeedback *feedback );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
static bool canUseLayer( const QgsRasterLayer *layer );
|
static bool canUseLayer( const QgsRasterLayer *layer );
|
||||||
|
@ -333,6 +333,7 @@ class TestQgsProcessing: public QObject
|
|||||||
void modelExecution();
|
void modelExecution();
|
||||||
void modelAcceptableValues();
|
void modelAcceptableValues();
|
||||||
void tempUtils();
|
void tempUtils();
|
||||||
|
void convertCompatible();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -5039,5 +5040,80 @@ void TestQgsProcessing::tempUtils()
|
|||||||
QVERIFY( tempFile2.startsWith( tempFolder ) );
|
QVERIFY( tempFile2.startsWith( tempFolder ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestQgsProcessing::convertCompatible()
|
||||||
|
{
|
||||||
|
// start with a compatible shapefile
|
||||||
|
QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/'; //defined in CmakeLists.txt
|
||||||
|
QString vector = testDataDir + "points.shp";
|
||||||
|
QgsVectorLayer *layer = new QgsVectorLayer( vector, "vl" );
|
||||||
|
QgsProject p;
|
||||||
|
p.addMapLayer( layer );
|
||||||
|
|
||||||
|
QgsProcessingContext context;
|
||||||
|
context.setProject( &p );
|
||||||
|
QgsProcessingFeedback feedback;
|
||||||
|
QString out = QgsProcessingUtils::convertToCompatibleFormat( layer, false, QStringLiteral( "test" ), QStringList() << "shp", QString( "shp" ), context, &feedback );
|
||||||
|
// layer should be returned unchanged - underlying source is compatible
|
||||||
|
QCOMPARE( out, layer->source() );
|
||||||
|
|
||||||
|
// don't include shp as compatible type
|
||||||
|
out = QgsProcessingUtils::convertToCompatibleFormat( layer, false, QStringLiteral( "test" ), QStringList() << "tab", QString( "tab" ), context, &feedback );
|
||||||
|
QVERIFY( out != layer->source() );
|
||||||
|
QVERIFY( out.endsWith( ".tab" ) );
|
||||||
|
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||||
|
|
||||||
|
// make sure all features are copied
|
||||||
|
QgsVectorLayer *t = new QgsVectorLayer( out, "vl2" );
|
||||||
|
QCOMPARE( layer->featureCount(), t->featureCount() );
|
||||||
|
QCOMPARE( layer->crs(), t->crs() );
|
||||||
|
|
||||||
|
// use a selection - this will require translation
|
||||||
|
QgsFeatureIds ids;
|
||||||
|
QgsFeature f;
|
||||||
|
QgsFeatureIterator it = layer->getFeatures();
|
||||||
|
it.nextFeature( f );
|
||||||
|
ids.insert( f.id() );
|
||||||
|
it.nextFeature( f );
|
||||||
|
ids.insert( f.id() );
|
||||||
|
|
||||||
|
layer->selectByIds( ids );
|
||||||
|
out = QgsProcessingUtils::convertToCompatibleFormat( layer, true, QStringLiteral( "test" ), QStringList() << "tab", QString( "tab" ), context, &feedback );
|
||||||
|
QVERIFY( out != layer->source() );
|
||||||
|
QVERIFY( out.endsWith( ".tab" ) );
|
||||||
|
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||||
|
delete t;
|
||||||
|
t = new QgsVectorLayer( out, "vl2" );
|
||||||
|
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||||
|
|
||||||
|
// 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() );
|
||||||
|
QVERIFY( out.endsWith( ".shp" ) );
|
||||||
|
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||||
|
delete t;
|
||||||
|
t = new QgsVectorLayer( out, "vl2" );
|
||||||
|
QCOMPARE( t->featureCount(), static_cast< long >( ids.count() ) );
|
||||||
|
|
||||||
|
|
||||||
|
// 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, layer->source() );
|
||||||
|
|
||||||
|
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() ) );
|
||||||
|
|
||||||
|
// selected only, will force export
|
||||||
|
params.insert( QStringLiteral( "source" ), QgsProcessingFeatureSourceDefinition( layer->id(), true ) );
|
||||||
|
out = QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( def.get(), params, context, QStringList() << "shp", QString( "shp" ), &feedback );
|
||||||
|
QVERIFY( out != layer->source() );
|
||||||
|
QVERIFY( out.endsWith( ".shp" ) );
|
||||||
|
QVERIFY( out.startsWith( QgsProcessingUtils::tempFolder() ) );
|
||||||
|
}
|
||||||
|
|
||||||
QGSTEST_MAIN( TestQgsProcessing )
|
QGSTEST_MAIN( TestQgsProcessing )
|
||||||
#include "testqgsprocessing.moc"
|
#include "testqgsprocessing.moc"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user