diff --git a/python/core/auto_generated/processing/qgsprocessingcontext.sip.in b/python/core/auto_generated/processing/qgsprocessingcontext.sip.in
index f03ff9988df..34e0be8fa1b 100644
--- a/python/core/auto_generated/processing/qgsprocessingcontext.sip.in
+++ b/python/core/auto_generated/processing/qgsprocessingcontext.sip.in
@@ -160,6 +160,13 @@ Ownership of ``processor`` is transferred.
.. seealso:: :py:func:`postProcessor`
.. versionadded:: 3.2
+%End
+
+ void setOutputLayerName( QgsMapLayer *layer ) const;
+%Docstring
+Sets a ``layer`` name to match this output, respecting any local user settings which affect this name.
+
+.. versionadded:: 3.10.1
%End
QgsProject *project;
diff --git a/python/plugins/processing/core/ProcessingConfig.py b/python/plugins/processing/core/ProcessingConfig.py
index e766a855a49..1d289497b58 100644
--- a/python/plugins/processing/core/ProcessingConfig.py
+++ b/python/plugins/processing/core/ProcessingConfig.py
@@ -49,7 +49,7 @@ class ProcessingConfig:
VECTOR_LINE_STYLE = 'VECTOR_LINE_STYLE'
VECTOR_POLYGON_STYLE = 'VECTOR_POLYGON_STYLE'
FILTER_INVALID_GEOMETRIES = 'FILTER_INVALID_GEOMETRIES'
- USE_FILENAME_AS_LAYER_NAME = 'USE_FILENAME_AS_LAYER_NAME'
+ PREFER_FILENAME_AS_LAYER_NAME = 'PREFER_FILENAME_AS_LAYER_NAME'
KEEP_DIALOG_OPEN = 'KEEP_DIALOG_OPEN'
PRE_EXECUTION_SCRIPT = 'PRE_EXECUTION_SCRIPT'
POST_EXECUTION_SCRIPT = 'POST_EXECUTION_SCRIPT'
@@ -74,8 +74,8 @@ class ProcessingConfig:
ProcessingConfig.tr('Keep dialog open after running an algorithm'), True))
ProcessingConfig.addSetting(Setting(
ProcessingConfig.tr('General'),
- ProcessingConfig.USE_FILENAME_AS_LAYER_NAME,
- ProcessingConfig.tr('Use filename as layer name'), False))
+ ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME,
+ ProcessingConfig.tr('Prefer output filename for layer names'), True))
ProcessingConfig.addSetting(Setting(
ProcessingConfig.tr('General'),
ProcessingConfig.SHOW_PROVIDERS_TOOLTIP,
diff --git a/python/plugins/processing/gui/Postprocessing.py b/python/plugins/processing/gui/Postprocessing.py
index 9029f5606b3..395f9d5bbf5 100644
--- a/python/plugins/processing/gui/Postprocessing.py
+++ b/python/plugins/processing/gui/Postprocessing.py
@@ -17,7 +17,6 @@
***************************************************************************
"""
-
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
@@ -41,30 +40,6 @@ from processing.core.ProcessingConfig import ProcessingConfig
from processing.gui.RenderingStyles import RenderingStyles
-def set_layer_name(layer, context_layer_details):
- """
- Sets the name for the given layer, either using the layer's file name
- (or database layer name), or the name specified by the parameter definition.
- """
- use_filename_as_layer_name = ProcessingConfig.getSetting(ProcessingConfig.USE_FILENAME_AS_LAYER_NAME)
-
- if use_filename_as_layer_name or not context_layer_details.name:
- source_parts = QgsProviderRegistry.instance().decodeUri(layer.dataProvider().name(), layer.source())
- layer_name = source_parts.get('layerName', '')
- # if source layer name exists, use that -- else use
- if layer_name:
- layer.setName(layer_name)
- else:
- path = source_parts.get('path', '')
- if path:
- layer.setName(os.path.splitext(os.path.basename(path))[0])
- elif context_layer_details.name:
- # fallback to parameter's name -- shouldn't happen!
- layer.setName(context_layer_details.name)
- else:
- layer.setName(context_layer_details.name)
-
-
def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parameters={}):
wrongLayers = []
if feedback is None:
@@ -82,7 +57,7 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parame
try:
layer = QgsProcessingUtils.mapLayerFromString(l, context, typeHint=details.layerTypeHint)
if layer is not None:
- set_layer_name(layer, details)
+ details.setOutputLayerName(layer)
'''If running a model, the execution will arrive here when an algorithm that is part of
that model is executed. We check if its output is a final otuput of the model, and
@@ -126,7 +101,9 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parame
else:
wrongLayers.append(str(l))
except Exception:
- QgsMessageLog.logMessage(QCoreApplication.translate('Postprocessing', "Error loading result layer:") + "\n" + traceback.format_exc(), 'Processing', Qgis.Critical)
+ QgsMessageLog.logMessage(QCoreApplication.translate('Postprocessing',
+ "Error loading result layer:") + "\n" + traceback.format_exc(),
+ 'Processing', Qgis.Critical)
wrongLayers.append(str(l))
i += 1
@@ -135,7 +112,8 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True, parame
if wrongLayers:
msg = QCoreApplication.translate('Postprocessing', "The following layers were not correctly generated.")
msg += "
" + "".join(["- %s
" % lay for lay in wrongLayers]) + "
"
- msg += QCoreApplication.translate('Postprocessing', "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.")
+ msg += QCoreApplication.translate('Postprocessing',
+ "You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.")
feedback.reportError(msg)
return len(wrongLayers) == 0
diff --git a/src/core/processing/qgsprocessingcontext.cpp b/src/core/processing/qgsprocessingcontext.cpp
index 5065727336f..a6adb6b1459 100644
--- a/src/core/processing/qgsprocessingcontext.cpp
+++ b/src/core/processing/qgsprocessingcontext.cpp
@@ -17,6 +17,8 @@
#include "qgsprocessingcontext.h"
#include "qgsprocessingutils.h"
+#include "qgsproviderregistry.h"
+#include "qgssettings.h"
QgsProcessingContext::QgsProcessingContext()
: mPreferredVectorFormat( QgsProcessingUtils::defaultVectorExtension() )
@@ -119,3 +121,39 @@ void QgsProcessingContext::LayerDetails::setPostProcessor( QgsProcessingLayerPos
mPostProcessor = processor;
}
+
+void QgsProcessingContext::LayerDetails::setOutputLayerName( QgsMapLayer *layer ) const
+{
+ if ( !layer )
+ return;
+
+ const bool preferFilenameAsLayerName = QgsSettings().value( QStringLiteral( "Processing/Configuration/PREFER_FILENAME_AS_LAYER_NAME" ), true ).toBool();
+
+ // note - for temporary layers, we don't use the filename, regardless of user setting (it will be meaningless!)
+ if ( ( preferFilenameAsLayerName && !layer->isTemporary() ) || name.isEmpty() )
+ {
+ const QVariantMap sourceParts = QgsProviderRegistry::instance()->decodeUri( layer->providerType(), layer->source() );
+ const QString layerName = sourceParts.value( QStringLiteral( "layerName" ) ).toString();
+ // if output layer name exists, use that!
+ if ( !layerName.isEmpty() )
+ layer->setName( layerName );
+ else
+ {
+ const QString path = sourceParts.value( QStringLiteral( "path" ) ).toString();
+ if ( !path.isEmpty() )
+ {
+ const QFileInfo fi( path );
+ layer->setName( fi.baseName() );
+ }
+ else if ( !name.isEmpty() )
+ {
+ // fallback to parameter's name -- shouldn't happen!
+ layer->setName( name );
+ }
+ }
+ }
+ else
+ {
+ layer->setName( name );
+ }
+}
diff --git a/src/core/processing/qgsprocessingcontext.h b/src/core/processing/qgsprocessingcontext.h
index fa3eb50840f..d59112ec53f 100644
--- a/src/core/processing/qgsprocessingcontext.h
+++ b/src/core/processing/qgsprocessingcontext.h
@@ -172,10 +172,17 @@ class CORE_EXPORT QgsProcessingContext
//! Default constructor
LayerDetails() = default;
- //! Friendly name for layer, to use when loading layer into project.
+ /**
+ * Friendly name for layer, possibly for use when loading layer into project.
+ *
+ * \warning Instead of directly using this value, prefer to call setOutputLayerName() to
+ * generate a layer name which respects the user's local Processing settings.
+ */
QString name;
- //! Associated output name from algorithm which generated the layer.
+ /**
+ * Associated output name from algorithm which generated the layer.
+ */
QString outputName;
/**
@@ -202,6 +209,13 @@ class CORE_EXPORT QgsProcessingContext
*/
void setPostProcessor( QgsProcessingLayerPostProcessorInterface *processor SIP_TRANSFER );
+ /**
+ * Sets a \a layer name to match this output, respecting any local user settings which affect this name.
+ *
+ * \since QGIS 3.10.1
+ */
+ void setOutputLayerName( QgsMapLayer *layer ) const;
+
//! Destination project
QgsProject *project = nullptr;
diff --git a/tests/src/analysis/testqgsprocessing.cpp b/tests/src/analysis/testqgsprocessing.cpp
index 4ec30e95d56..075b9fafc86 100644
--- a/tests/src/analysis/testqgsprocessing.cpp
+++ b/tests/src/analysis/testqgsprocessing.cpp
@@ -1938,6 +1938,27 @@ void TestQgsProcessing::parameters()
QCOMPARE( context2.layersToLoadOnCompletion().keys().at( 0 ), destId );
QCOMPARE( context2.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "my_dest" ) );
QCOMPARE( context2.layersToLoadOnCompletion().values().at( 0 ).outputName, QStringLiteral( "fs" ) );
+
+ // setting layer name to match...
+ context2.layersToLoadOnCompletion().values().at( 0 ).setOutputLayerName( nullptr );
+ std::unique_ptr< QgsVectorLayer > vl = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "Point" ), QString(), QStringLiteral( "memory" ) );
+ QVERIFY( vl->isValid() );
+ context2.layersToLoadOnCompletion().values().at( 0 ).setOutputLayerName( vl.get() );
+ // temporary layer, must use output name as layer name
+ QCOMPARE( vl->name(), QStringLiteral( "my_dest" ) );
+ // otherwise expect to use path
+ std::unique_ptr< QgsRasterLayer > rl = qgis::make_unique< QgsRasterLayer >( QStringLiteral( TEST_DATA_DIR ) + "/landsat.tif", QString() );
+ context2.layersToLoadOnCompletion().values().at( 0 ).setOutputLayerName( rl.get() );
+ QCOMPARE( rl->name(), QStringLiteral( "landsat" ) );
+ // unless setting prohibits it...
+ QgsSettings().setValue( QStringLiteral( "Processing/Configuration/PREFER_FILENAME_AS_LAYER_NAME" ), false );
+ context2.layersToLoadOnCompletion().values().at( 0 ).setOutputLayerName( rl.get() );
+ QCOMPARE( rl->name(), QStringLiteral( "my_dest" ) );
+ // if layer has a layername, we should use that instead of the base file name...
+ QgsSettings().setValue( QStringLiteral( "Processing/Configuration/PREFER_FILENAME_AS_LAYER_NAME" ), true );
+ vl = qgis::make_unique< QgsVectorLayer >( QStringLiteral( TEST_DATA_DIR ) + "/points_gpkg.gpkg|layername=points_small", QString() );
+ context2.layersToLoadOnCompletion().values().at( 0 ).setOutputLayerName( vl.get() );
+ QCOMPARE( vl->name(), QStringLiteral( "points_small" ) );
}
void TestQgsProcessing::algorithmParameters()