diff --git a/python/plugins/processing/tools/system.py b/python/plugins/processing/tools/system.py index ebf7f954976..2632621f9a4 100644 --- a/python/plugins/processing/tools/system.py +++ b/python/plugins/processing/tools/system.py @@ -74,14 +74,6 @@ def tempFolder(): return str(os.path.abspath(tempDir)) -def setTempOutput(out, alg): - if hasattr(out, 'directory'): - out.value = getTempDirInTempFolder() - else: - ext = out.getDefaultFileExtension(alg) - out.value = getTempFilenameInTempFolder(out.name + '.' + ext) - - def getTempFilename(ext=None): tmpPath = tempFolder() t = time.time() diff --git a/src/core/processing/qgsprocessingalgorithm.cpp b/src/core/processing/qgsprocessingalgorithm.cpp index 360b550b036..8e1d67e0b14 100644 --- a/src/core/processing/qgsprocessingalgorithm.cpp +++ b/src/core/processing/qgsprocessingalgorithm.cpp @@ -95,6 +95,16 @@ QgsProcessingProvider *QgsProcessingAlgorithm::provider() const void QgsProcessingAlgorithm::setProvider( QgsProcessingProvider *provider ) { mProvider = provider; + + // need to update all destination parameters to set whether the provider supports non file based outputs + Q_FOREACH ( const QgsProcessingParameterDefinition *definition, mParameters ) + { + if ( definition->isDestination() && mProvider ) + { + const QgsProcessingDestinationParameter *destParam = static_cast< const QgsProcessingDestinationParameter *>( definition ); + const_cast< QgsProcessingDestinationParameter *>( destParam )->setSupportsNonFileBasedOutputs( mProvider->supportsNonFileBasedOutput() ); + } + } } QWidget *QgsProcessingAlgorithm::createCustomParametersWidget( QWidget * ) const @@ -214,7 +224,7 @@ bool QgsProcessingAlgorithm::addParameter( QgsProcessingParameterDefinition *def if ( QgsProcessingAlgorithm::parameterDefinition( definition->name() ) ) return false; - if ( definition->isDestination() ) + if ( definition->isDestination() && mProvider ) { QgsProcessingDestinationParameter *destParam = static_cast< QgsProcessingDestinationParameter *>( definition ); destParam->setSupportsNonFileBasedOutputs( mProvider->supportsNonFileBasedOutput() ); diff --git a/src/core/processing/qgsprocessingparameters.cpp b/src/core/processing/qgsprocessingparameters.cpp index 795e5afe51c..d4312baa1de 100644 --- a/src/core/processing/qgsprocessingparameters.cpp +++ b/src/core/processing/qgsprocessingparameters.cpp @@ -20,6 +20,7 @@ #include "qgsprocessingutils.h" #include "qgsvectorlayerfeatureiterator.h" #include "qgsprocessingoutputs.h" +#include "qgssettings.h" bool QgsProcessingParameters::isDynamic( const QVariantMap ¶meters, const QString &name ) { @@ -2057,6 +2058,19 @@ QgsProcessingOutputDefinition *QgsProcessingParameterFeatureSink::toOutputDefini return new QgsProcessingOutputVectorLayer( name(), description(), mDataType ); } +QString QgsProcessingParameterFeatureSink::defaultFileExtension() const +{ + QgsSettings settings; + if ( hasGeometry() ) + { + return settings.value( QStringLiteral( "Processing/DefaultOutputVectorLayerExt" ), QStringLiteral( "shp" ), QgsSettings::Core ).toString(); + } + else + { + return QStringLiteral( "dbf" ); + } +} + QgsProcessingParameterDefinition::LayerType QgsProcessingParameterFeatureSink::dataType() const { return mDataType; @@ -2156,6 +2170,12 @@ QgsProcessingOutputDefinition *QgsProcessingParameterRasterOutput::toOutputDefin return new QgsProcessingOutputRasterLayer( name(), description() ); } +QString QgsProcessingParameterRasterOutput::defaultFileExtension() const +{ + QgsSettings settings; + return settings.value( QStringLiteral( "Processing/DefaultOutputRasterLayerExt" ), QStringLiteral( "tif" ), QgsSettings::Core ).toString(); +} + QgsProcessingParameterFileOutput::QgsProcessingParameterFileOutput( const QString &name, const QString &description, const QString &fileFilter, const QVariant &defaultValue, bool optional ) : QgsProcessingDestinationParameter( name, description, defaultValue, optional ) @@ -2218,6 +2238,20 @@ QgsProcessingOutputDefinition *QgsProcessingParameterFileOutput::toOutputDefinit return nullptr; } +QString QgsProcessingParameterFileOutput::defaultFileExtension() const +{ + if ( mFileFilter.isEmpty() || mFileFilter == QObject::tr( "All files (*.*)" ) ) + return QStringLiteral( "file" ); + + // get first extension from filter + QRegularExpression rx( ".*?\\(\\*\\.([a-zA-Z0-9._]+).*" ); + QRegularExpressionMatch match = rx.match( mFileFilter ); + if ( !match.hasMatch() ) + return QStringLiteral( "file" ); + + return match.captured( 1 ); +} + QString QgsProcessingParameterFileOutput::fileFilter() const { return mFileFilter; @@ -2272,6 +2306,11 @@ QgsProcessingOutputDefinition *QgsProcessingParameterFolderOutput::toOutputDefin return nullptr; } +QString QgsProcessingParameterFolderOutput::defaultFileExtension() const +{ + return QString(); +} + QgsProcessingDestinationParameter::QgsProcessingDestinationParameter( const QString &name, const QString &description, const QVariant &defaultValue, bool optional ) : QgsProcessingParameterDefinition( name, description, defaultValue, optional ) { @@ -2281,7 +2320,7 @@ QgsProcessingDestinationParameter::QgsProcessingDestinationParameter( const QStr QVariantMap QgsProcessingDestinationParameter::toVariantMap() const { QVariantMap map = QgsProcessingParameterDefinition::toVariantMap(); - map.insert( QStringLiteral( "support_non_file_outputs" ), mSupportsNonFileBasedOutputs ); + map.insert( QStringLiteral( "supports_non_file_outputs" ), mSupportsNonFileBasedOutputs ); return map; } diff --git a/src/core/processing/qgsprocessingparameters.h b/src/core/processing/qgsprocessingparameters.h index 702630e0911..27741539807 100644 --- a/src/core/processing/qgsprocessingparameters.h +++ b/src/core/processing/qgsprocessingparameters.h @@ -1307,6 +1307,12 @@ class CORE_EXPORT QgsProcessingDestinationParameter : public QgsProcessingParame */ void setSupportsNonFileBasedOutputs( bool supportsNonFileBasedOutputs ) { mSupportsNonFileBasedOutputs = supportsNonFileBasedOutputs; } + /** + * Returns the default file extension for destination file paths + * associated with this parameter. + */ + virtual QString defaultFileExtension() const = 0; + private: bool mSupportsNonFileBasedOutputs = true; @@ -1336,6 +1342,7 @@ class CORE_EXPORT QgsProcessingParameterFeatureSink : public QgsProcessingDestin bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override; QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override; QgsProcessingOutputDefinition *toOutputDefinition() const override SIP_FACTORY; + QString defaultFileExtension() const override; /** * Returns the layer type for sinks associated with the parameter. @@ -1433,6 +1440,7 @@ class CORE_EXPORT QgsProcessingParameterRasterOutput : public QgsProcessingDesti bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override; QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override; QgsProcessingOutputDefinition *toOutputDefinition() const override SIP_FACTORY; + QString defaultFileExtension() const override; }; /** @@ -1457,6 +1465,7 @@ class CORE_EXPORT QgsProcessingParameterFileOutput : public QgsProcessingDestina bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override; QString valueAsPythonString( const QVariant &value, QgsProcessingContext &context ) const override; QgsProcessingOutputDefinition *toOutputDefinition() const override SIP_FACTORY; + QString defaultFileExtension() const override; /** * Returns the file filter string for files compatible with this output. @@ -1498,6 +1507,7 @@ class CORE_EXPORT QgsProcessingParameterFolderOutput : public QgsProcessingDesti QString type() const override { return QStringLiteral( "folderOut" ); } bool checkValueIsAcceptable( const QVariant &input, QgsProcessingContext *context = nullptr ) const override; QgsProcessingOutputDefinition *toOutputDefinition() const override SIP_FACTORY; + QString defaultFileExtension() const override; }; diff --git a/tests/src/core/testqgsprocessing.cpp b/tests/src/core/testqgsprocessing.cpp index 9556d100208..21f6d956d91 100644 --- a/tests/src/core/testqgsprocessing.cpp +++ b/tests/src/core/testqgsprocessing.cpp @@ -106,13 +106,6 @@ class DummyAlgorithm : public QgsProcessingAlgorithm QVERIFY( addParameter( p6 ) ); QCOMPARE( destinationParameterDefinitions(), QgsProcessingParameterDefinitions() << p5 << p6 ); - // check that supportsNonFileBasedOutputs flags is set automatically to match provider - // when adding a destination parameter - QgsProcessingParameterFeatureSink *p7 = new QgsProcessingParameterFeatureSink( "p7" ); - p7->setSupportsNonFileBasedOutputs( false ); - QVERIFY( addParameter( p7 ) ); - QVERIFY( destinationParameterDefinitions().at( 2 )->supportsNonFileBasedOutputs() ); - // remove parameter removeParameter( "non existent" ); removeParameter( "p6" ); @@ -346,6 +339,11 @@ void TestQgsProcessing::initTestCase() { QgsApplication::init(); QgsApplication::initQgis(); + + // Set up the QgsSettings environment + QCoreApplication::setOrganizationName( QStringLiteral( "QGIS" ) ); + QCoreApplication::setOrganizationDomain( QStringLiteral( "qgis.org" ) ); + QCoreApplication::setApplicationName( QStringLiteral( "QGIS-TEST" ) ); } void TestQgsProcessing::cleanupTestCase() @@ -2812,6 +2810,8 @@ void TestQgsProcessing::parameterFeatureSink() QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProcessingOutputLayerDefinition( QgsProperty::fromExpression( "\"abc\" || \"def\"" ) ) ), context ), QStringLiteral( "QgsProcessingOutputLayerDefinition(QgsProperty.fromExpression('\"abc\" || \"def\"'))" ) ); QCOMPARE( def->valueAsPythonString( QVariant::fromValue( QgsProperty::fromExpression( "\"a\"=1" ) ), context ), QStringLiteral( "QgsProperty.fromExpression('\"a\"=1')" ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "shp" ) ); + QVariantMap map = def->toVariantMap(); QgsProcessingParameterFeatureSink fromMap( "x" ); QVERIFY( fromMap.fromVariantMap( map ) ); @@ -2931,6 +2931,8 @@ void TestQgsProcessing::parameterRasterOut() QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.tif" ) ); QVERIFY( def->checkValueIsAcceptable( "c:/Users/admin/Desktop/roads_clipped_transformed_v1_reprojected_final_clipped_aAAA.tif", &context ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "tif" ) ); + QVariantMap params; params.insert( "non_optional", "test.tif" ); QCOMPARE( QgsProcessingParameters::parameterAsRasterOutputLayer( def.get(), params, context ), QStringLiteral( "test.tif" ) ); @@ -2981,8 +2983,16 @@ void TestQgsProcessing::parameterFileOut() // not optional! std::unique_ptr< QgsProcessingParameterFileOutput > def( new QgsProcessingParameterFileOutput( "non_optional", QString(), QStringLiteral( "BMP files (*.bmp)" ), QString(), false ) ); QCOMPARE( def->fileFilter(), QStringLiteral( "BMP files (*.bmp)" ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "bmp" ) ); def->setFileFilter( QStringLiteral( "PCX files (*.pcx)" ) ); QCOMPARE( def->fileFilter(), QStringLiteral( "PCX files (*.pcx)" ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "pcx" ) ); + def->setFileFilter( QStringLiteral( "PCX files (*.pcx *.picx)" ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "pcx" ) ); + def->setFileFilter( QStringLiteral( "PCX files (*.pcx *.picx);;BMP files (*.bmp)" ) ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "pcx" ) ); + def->setFileFilter( QString() ); + QCOMPARE( def->defaultFileExtension(), QStringLiteral( "file" ) ); QVERIFY( !def->checkValueIsAcceptable( false ) ); QVERIFY( !def->checkValueIsAcceptable( true ) );