@@ -128,8 +128,14 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
128
128
if not active_layer .selectedFeatureIds ():
129
129
active_layer .selectAll ()
130
130
131
+ # Make sure we are working on selected features only
132
+ parameters ['INPUT' ] = QgsProcessingFeatureSourceDefinition (active_layer .id (), True )
131
133
parameters ['OUTPUT' ] = 'memory:'
132
134
135
+ req = QgsFeatureRequest (QgsExpression (r"$id < 0" ))
136
+ req .setFlags (QgsFeatureRequest .NoGeometry )
137
+ req .setSubsetOfAttributes ([])
138
+
133
139
# Start the execution
134
140
# If anything goes wrong and raise_exceptions is True an exception
135
141
# is raised, else the execution is aborted and the error reported in
@@ -139,10 +145,6 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
139
145
140
146
active_layer .beginEditCommand (alg .displayName ())
141
147
142
- req = QgsFeatureRequest (QgsExpression (r"$id < 0" ))
143
- req .setFlags (QgsFeatureRequest .NoGeometry )
144
- req .setSubsetOfAttributes ([])
145
-
146
148
# Checks whether the algorithm has a processFeature method
147
149
if hasattr (alg , 'processFeature' ): # in-place feature editing
148
150
# Make a clone or it will crash the second time the dialog
@@ -154,7 +156,9 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
154
156
if not alg .supportInPlaceEdit (active_layer ):
155
157
raise QgsProcessingException (tr ("Selected algorithm and parameter configuration are not compatible with in-place modifications." ))
156
158
field_idxs = range (len (active_layer .fields ()))
157
- feature_iterator = active_layer .getFeatures (QgsFeatureRequest (active_layer .selectedFeatureIds ()))
159
+ iterator_req = QgsFeatureRequest (active_layer .selectedFeatureIds ())
160
+ iterator_req .setInvalidGeometryCheck (context .invalidGeometryCheck ())
161
+ feature_iterator = active_layer .getFeatures (iterator_req )
158
162
step = 100 / len (active_layer .selectedFeatureIds ()) if active_layer .selectedFeatureIds () else 1
159
163
for current , f in enumerate (feature_iterator ):
160
164
feedback .setProgress (current * step )
@@ -166,6 +170,7 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
166
170
input_feature = QgsFeature (f )
167
171
new_features = alg .processFeature (input_feature , context , feedback )
168
172
new_features = QgsVectorLayerUtils .makeFeaturesCompatible (new_features , active_layer )
173
+
169
174
if len (new_features ) == 0 :
170
175
active_layer .deleteFeature (f .id ())
171
176
elif len (new_features ) == 1 :
@@ -178,7 +183,7 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
178
183
else :
179
184
active_layer .deleteFeature (f .id ())
180
185
# Get the new ids
181
- old_ids = set ([f .id () for f in active_layer .getFeatures (req )])
186
+ old_ids = set ([f .id () for f in active_layer .getFeatures ()])
182
187
if not active_layer .addFeatures (new_features ):
183
188
raise QgsProcessingException (tr ("Error adding processed features back into the layer." ))
184
189
new_ids = set ([f .id () for f in active_layer .getFeatures (req )])
@@ -187,13 +192,32 @@ def execute_in_place_run(alg, parameters, context=None, feedback=None, raise_exc
187
192
results , ok = {}, True
188
193
189
194
else : # Traditional 'run' with delete and add features cycle
195
+
196
+ # There is no way to know if some features have been skipped
197
+ # due to invalid geometries
198
+ if context .invalidGeometryCheck () == QgsFeatureRequest .GeometrySkipInvalid :
199
+ selected_ids = active_layer .selectedFeatureIds ()
200
+ else :
201
+ selected_ids = []
202
+
190
203
results , ok = alg .run (parameters , context , feedback )
191
204
192
205
if ok :
193
206
result_layer = QgsProcessingUtils .mapLayerFromString (results ['OUTPUT' ], context )
194
207
# TODO: check if features have changed before delete/add cycle
195
- active_layer . deleteFeatures ( active_layer . selectedFeatureIds ())
208
+
196
209
new_features = []
210
+
211
+ # Check if there are any skipped features
212
+ if context .invalidGeometryCheck () == QgsFeatureRequest .GeometrySkipInvalid :
213
+ missing_ids = list (set (selected_ids ) - set (result_layer .allFeatureIds ()))
214
+ if missing_ids :
215
+ for f in active_layer .getFeatures (QgsFeatureRequest (missing_ids )):
216
+ if not f .geometry ().isGeosValid ():
217
+ new_features .append (f )
218
+
219
+ active_layer .deleteFeatures (active_layer .selectedFeatureIds ())
220
+
197
221
for f in result_layer .getFeatures ():
198
222
new_features .extend (QgsVectorLayerUtils .
199
223
makeFeaturesCompatible ([f ], active_layer ))
@@ -248,7 +272,12 @@ def execute_in_place(alg, parameters, context=None, feedback=None):
248
272
parameters ['INPUT' ] = iface .activeLayer ()
249
273
ok , results = execute_in_place_run (alg , parameters , context = context , feedback = feedback )
250
274
if ok :
251
- parameters ['INPUT' ].triggerRepaint ()
275
+ if isinstance (parameters ['INPUT' ], QgsProcessingFeatureSourceDefinition ):
276
+ layer = alg .parameterAsVectorLayer ({'INPUT' : parameters ['INPUT' ].source }, 'INPUT' , context )
277
+ elif isinstance (parameters ['INPUT' ], QgsVectorLayer ):
278
+ layer = parameters ['INPUT' ]
279
+ if layer :
280
+ layer .triggerRepaint ()
252
281
return ok , results
253
282
254
283
0 commit comments