diff --git a/python/plugins/processing/gui/AlgorithmDialog.py b/python/plugins/processing/gui/AlgorithmDialog.py index 1460ee95126..5eb572c3a89 100644 --- a/python/plugins/processing/gui/AlgorithmDialog.py +++ b/python/plugins/processing/gui/AlgorithmDialog.py @@ -71,6 +71,7 @@ class AlgorithmDialog(QgsProcessingAlgorithmDialogBase): self.feedback_dialog = None self.in_place = in_place + self.active_layer = iface.activeLayer() self.setAlgorithm(alg) self.setMainWidget(self.getParametersPanel(alg, self)) @@ -81,10 +82,11 @@ class AlgorithmDialog(QgsProcessingAlgorithmDialogBase): self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole) # reset role to ensure left alignment else: self.runAsBatchButton = None - has_selection = iface.activeLayer() and (iface.activeLayer().selectedFeatureCount() > 0) + has_selection = self.active_layer and (self.active_layer.selectedFeatureCount() > 0) self.buttonBox().button(QDialogButtonBox.Ok).setText(QCoreApplication.translate("AlgorithmDialog", "Modify Selected Features") if has_selection else QCoreApplication.translate("AlgorithmDialog", "Modify All Features")) self.buttonBox().button(QDialogButtonBox.Close).setText(QCoreApplication.translate("AlgorithmDialog", "Cancel")) + self.setWindowTitle(self.windowTitle() + ' | ' + self.active_layer.name()) def getParametersPanel(self, alg, parent): return ParametersPanel(parent, alg, self.in_place) @@ -110,7 +112,7 @@ class AlgorithmDialog(QgsProcessingAlgorithmDialogBase): if not param.isDestination(): if self.in_place and param.name() == 'INPUT': - parameters[param.name()] = iface.activeLayer() + parameters[param.name()] = self.active_layer continue try: diff --git a/python/plugins/processing/gui/AlgorithmExecutor.py b/python/plugins/processing/gui/AlgorithmExecutor.py index 39c3f7fc6a4..563cbe51ac6 100644 --- a/python/plugins/processing/gui/AlgorithmExecutor.py +++ b/python/plugins/processing/gui/AlgorithmExecutor.py @@ -41,7 +41,8 @@ from qgis.core import (Qgis, QgsExpression, QgsWkbTypes, QgsGeometry, - QgsVectorLayerUtils) + QgsVectorLayerUtils, + QgsVectorLayer) from processing.gui.Postprocessing import handleAlgorithmResults from processing.tools import dataobjects from qgis.utils import iface @@ -70,13 +71,11 @@ def execute(alg, parameters, context=None, feedback=None): return False, {} -def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=None, raise_exceptions=False): +def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exceptions=False): """Executes an algorithm modifying features in-place in the input layer. :param alg: algorithm to run :type alg: QgsProcessingAlgorithm - :param active_layer: the editable layer - :type active_layer: QgsVectoLayer :param parameters: parameters of the algorithm :type parameters: dict :param context: context, defaults to None @@ -95,6 +94,8 @@ def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=N if context is None: context = dataobjects.createContext(feedback) + active_layer = parameters['INPUT'] + # Run some checks and prepare the layer for in-place execution by: # - getting the active layer and checking that it is a vector # - making the layer editable if it was not already @@ -107,6 +108,9 @@ def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=N if active_layer is None: raise QgsProcessingException(tr("There is not active layer.")) + if not isinstance(active_layer, QgsVectorLayer): + raise QgsProcessingException(tr("Active layer is not a vector layer.")) + if not active_layer.isEditable(): if not active_layer.startEditing(): raise QgsProcessingException(tr("Active layer is not editable (and editing could not be turned on).")) @@ -150,7 +154,7 @@ def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=N if not alg.supportInPlaceEdit(active_layer): raise QgsProcessingException(tr("Selected algorithm and parameter configuration are not compatible with in-place modifications.")) field_idxs = range(len(active_layer.fields())) - feature_iterator = active_layer.getFeatures(QgsFeatureRequest(active_layer.selectedFeatureIds())) if parameters['INPUT'].selectedFeaturesOnly else active_layer.getFeatures() + feature_iterator = active_layer.getFeatures(QgsFeatureRequest(active_layer.selectedFeatureIds())) step = 100 / len(active_layer.selectedFeatureIds()) if active_layer.selectedFeatureIds() else 1 for current, f in enumerate(feature_iterator): feedback.setProgress(current * step) @@ -223,7 +227,9 @@ def execute_in_place_run(alg, active_layer, parameters, context=None, feedback=N def execute_in_place(alg, parameters, context=None, feedback=None): - """Executes an algorithm modifying features in-place in the active layer. + """Executes an algorithm modifying features in-place, if the INPUT + parameter is not defined, the current active layer will be used as + INPUT. :param alg: algorithm to run :type alg: QgsProcessingAlgorithm @@ -238,10 +244,11 @@ def execute_in_place(alg, parameters, context=None, feedback=None): :rtype: tuple """ - parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(iface.activeLayer().id(), True) - ok, results = execute_in_place_run(alg, iface.activeLayer(), parameters, context=context, feedback=feedback) + if not 'INPUT' in parameters or not parameters['INPUT']: + parameters['INPUT'] = iface.activeLayer() + ok, results = execute_in_place_run(alg, parameters, context=context, feedback=feedback) if ok: - iface.activeLayer().triggerRepaint() + parameters['INPUT'].triggerRepaint() return ok, results diff --git a/tests/src/python/test_qgsprocessinginplace.py b/tests/src/python/test_qgsprocessinginplace.py index 07c1a04cef2..ad44a4f492a 100644 --- a/tests/src/python/test_qgsprocessinginplace.py +++ b/tests/src/python/test_qgsprocessinginplace.py @@ -349,8 +349,7 @@ class TestQgsProcessingInPlace(unittest.TestCase): alg = self.registry.createAlgorithmById(alg_name) self.assertIsNotNone(alg) - parameters['INPUT'] = QgsProcessingFeatureSourceDefinition( - input_layer.id(), True) + parameters['INPUT'] = input_layer parameters['OUTPUT'] = 'memory:' old_features = [f for f in input_layer.getFeatures()] @@ -365,7 +364,7 @@ class TestQgsProcessingInPlace(unittest.TestCase): input_layer.rollBack() ok = False ok, _ = execute_in_place_run( - alg, input_layer, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True) new_features = [f for f in input_layer.getFeatures()] # Check ret values @@ -453,14 +452,13 @@ class TestQgsProcessingInPlace(unittest.TestCase): 'DELTA_X': 1.1, 'DELTA_Y': 1.1, } - parameters['INPUT'] = QgsProcessingFeatureSourceDefinition( - self.vl.id(), True) + parameters['INPUT'] = self.vl parameters['OUTPUT'] = 'memory:' old_features = [f for f in self.vl.getFeatures()] ok, _ = execute_in_place_run( - alg, self.vl, parameters, context=context, feedback=feedback, raise_exceptions=True) + alg, parameters, context=context, feedback=feedback, raise_exceptions=True) new_features = [f for f in self.vl.getFeatures()] self.assertEqual(len(new_features), old_count)