Skip to content

Commit 681d44f

Browse files
committedSep 14, 2018
Messy mockup of feature
1 parent 34e29b5 commit 681d44f

19 files changed

+301
-14
lines changed
 

‎python/core/auto_generated/processing/qgsprocessingalgorithm.sip.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ Abstract base class for processing algorithms.
4444
FlagRequiresMatchingCrs,
4545
FlagNoThreading,
4646
FlagDisplayNameIsLiteral,
47+
FlagSupportsInPlaceEdits,
4748
FlagDeprecated,
4849
};
4950
typedef QFlags<QgsProcessingAlgorithm::Flag> Flags;
@@ -853,6 +854,9 @@ algorithm in "chains", avoiding the need for temporary outputs in multi-step mod
853854
Constructor for QgsProcessingFeatureBasedAlgorithm.
854855
%End
855856

857+
virtual QgsProcessingAlgorithm::Flags flags() const;
858+
859+
856860
protected:
857861

858862
virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() );

‎python/gui/auto_generated/processing/qgsprocessingtoolboxmodel.sip.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ the results.
379379
{
380380
FilterToolbox,
381381
FilterModeler,
382+
FilterInPlace,
382383
};
383384
typedef QFlags<QgsProcessingToolboxProxyModel::Filter> Filters;
384385

@@ -417,6 +418,8 @@ Returns any filters that affect how toolbox content is filtered.
417418
.. seealso:: :py:func:`setFilters`
418419
%End
419420

421+
void setInPlaceLayerType( QgsWkbTypes::GeometryType type );
422+
420423
void setFilterString( const QString &filter );
421424
%Docstring
422425
Sets a ``filter`` string, such that only algorithms matching the

‎python/gui/auto_generated/processing/qgsprocessingtoolboxtreeview.sip.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ if no algorithm is currently selected.
7373
Sets ``filters`` controlling the view's contents.
7474
%End
7575

76+
void setInPlaceLayerType( QgsWkbTypes::GeometryType type );
77+
7678
public slots:
7779

7880
void setFilterString( const QString &filter );

‎python/plugins/processing/ProcessingPlugin.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
QgsDataItemProvider,
3636
QgsDataProvider,
3737
QgsDataItem,
38+
QgsMapLayer,
3839
QgsMimeDataUtils)
3940
from qgis.gui import (QgsOptionsWidgetFactory,
4041
QgsCustomDropHandler)
@@ -48,7 +49,8 @@
4849
from processing.gui.HistoryDialog import HistoryDialog
4950
from processing.gui.ConfigDialog import ConfigOptionsPage
5051
from processing.gui.ResultsDock import ResultsDock
51-
from processing.gui.AlgorithmLocatorFilter import AlgorithmLocatorFilter
52+
from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter,
53+
InPlaceAlgorithmLocatorFilter)
5254
from processing.modeler.ModelerDialog import ModelerDialog
5355
from processing.tools.system import tempHelpFolder
5456
from processing.gui.menus import removeMenus, initializeMenus, createMenus
@@ -168,6 +170,8 @@ def __init__(self, iface):
168170
QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider)
169171
self.locator_filter = AlgorithmLocatorFilter()
170172
iface.registerLocatorFilter(self.locator_filter)
173+
self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter()
174+
iface.registerLocatorFilter(self.edit_features_locator_filter)
171175
Processing.initialize()
172176

173177
def initGui(self):
@@ -233,6 +237,14 @@ def initGui(self):
233237
self.optionsAction.triggered.connect(self.openProcessingOptions)
234238
self.toolbox.processingToolbar.addAction(self.optionsAction)
235239

240+
self.editSelectedAction = QAction(
241+
QgsApplication.getThemeIcon("/mActionToggleEditing.svg"),
242+
self.tr('Edit Selected Features'), self.iface.mainWindow())
243+
self.editSelectedAction.setObjectName('editSelectedFeatures')
244+
self.editSelectedAction.setCheckable(True)
245+
self.editSelectedAction.toggled.connect(self.editSelected)
246+
self.toolbox.processingToolbar.addAction(self.editSelectedAction)
247+
236248
menuBar = self.iface.mainWindow().menuBar()
237249
menuBar.insertMenu(
238250
self.iface.firstRightStandardMenu().menuAction(), self.menu)
@@ -242,6 +254,15 @@ def initGui(self):
242254
initializeMenus()
243255
createMenus()
244256

257+
self.iface.currentLayerChanged.connect(self.layer_changed)
258+
259+
def layer_changed(self, layer):
260+
if layer is None or layer.type() != QgsMapLayer.VectorLayer or not layer.isEditable() or not layer.selectedFeatureCount():
261+
self.editSelectedAction.setChecked(False)
262+
self.editSelectedAction.setEnabled(False)
263+
else:
264+
self.editSelectedAction.setEnabled(True)
265+
245266
def openProcessingOptions(self):
246267
self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions')
247268

@@ -273,6 +294,7 @@ def unload(self):
273294

274295
self.iface.unregisterOptionsWidgetFactory(self.options_factory)
275296
self.iface.deregisterLocatorFilter(self.locator_filter)
297+
self.iface.deregisterLocatorFilter(self.edit_features_locator_filter)
276298
self.iface.unregisterCustomDropHandler(self.drop_handler)
277299
QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider)
278300

@@ -306,3 +328,6 @@ def openHistory(self):
306328

307329
def tr(self, message):
308330
return QCoreApplication.translate('ProcessingPlugin', message)
331+
332+
def editSelected(self, enabled):
333+
self.toolbox.set_in_place_edit_mode(enabled)

‎python/plugins/processing/algs/qgis/AddTableField.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from qgis.PyQt.QtCore import QVariant
2929
from qgis.core import (QgsField,
3030
QgsProcessing,
31+
QgsProcessingAlgorithm,
3132
QgsProcessingParameterString,
3233
QgsProcessingParameterNumber,
3334
QgsProcessingParameterEnum,
@@ -57,6 +58,9 @@ def __init__(self):
5758
self.tr('String')]
5859
self.field = None
5960

61+
def flags(self):
62+
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits
63+
6064
def initParameters(self, config=None):
6165
self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
6266
self.tr('Field name')))

‎python/plugins/processing/algs/qgis/DeleteColumn.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from qgis.core import (QgsProcessingParameterField,
3131
QgsProcessing,
32+
QgsProcessingAlgorithm,
3233
QgsProcessingFeatureSource)
3334
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
3435

@@ -37,6 +38,9 @@ class DeleteColumn(QgisFeatureBasedAlgorithm):
3738

3839
COLUMNS = 'COLUMN'
3940

41+
def flags(self):
42+
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits
43+
4044
def tags(self):
4145
return self.tr('drop,delete,remove,fields,columns,attributes').split(',')
4246

‎python/plugins/processing/algs/qgis/GeometryByExpression.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
QgsExpression,
3030
QgsGeometry,
3131
QgsProcessing,
32+
QgsProcessingAlgorithm,
3233
QgsProcessingException,
3334
QgsProcessingParameterBoolean,
3435
QgsProcessingParameterEnum,
@@ -51,6 +52,9 @@ def group(self):
5152
def groupId(self):
5253
return 'vectorgeometry'
5354

55+
def flags(self):
56+
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits
57+
5458
def __init__(self):
5559
super().__init__()
5660
self.geometry_types = [self.tr('Polygon'),

‎python/plugins/processing/gui/AlgorithmDialog.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
from processing.gui.ParametersPanel import ParametersPanel
5858
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
5959
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
60-
from processing.gui.AlgorithmExecutor import executeIterating, execute
60+
from processing.gui.AlgorithmExecutor import executeIterating, execute, execute_in_place
6161
from processing.gui.Postprocessing import handleAlgorithmResults
6262
from processing.gui.wrappers import WidgetWrapper
6363

@@ -66,19 +66,25 @@
6666

6767
class AlgorithmDialog(QgsProcessingAlgorithmDialogBase):
6868

69-
def __init__(self, alg):
69+
def __init__(self, alg, in_place=False):
7070
super().__init__()
7171
self.feedback_dialog = None
72+
self.in_place = in_place
7273

7374
self.setAlgorithm(alg)
7475
self.setMainWidget(self.getParametersPanel(alg, self))
7576

76-
self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
77-
self.runAsBatchButton.clicked.connect(self.runAsBatch)
78-
self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole) # reset role to ensure left alignment
77+
if not self.in_place:
78+
self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
79+
self.runAsBatchButton.clicked.connect(self.runAsBatch)
80+
self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole) # reset role to ensure left alignment
81+
else:
82+
self.runAsBatchButton = None
83+
self.buttonBox().button(QDialogButtonBox.Ok).setText('Modify Selected Features')
84+
self.buttonBox().button(QDialogButtonBox.Close).setText('Cancel')
7985

8086
def getParametersPanel(self, alg, parent):
81-
return ParametersPanel(parent, alg)
87+
return ParametersPanel(parent, alg, self.in_place)
8288

8389
def runAsBatch(self):
8490
self.close()
@@ -118,10 +124,23 @@ def getParameterValues(self):
118124

119125
value = wrapper.parameterValue()
120126
parameters[param.name()] = value
127+
if self.in_place and param.name() == 'INPUT':
128+
parameters[param.name()] = iface.activeLayer()
129+
continue
130+
131+
wrapper = self.mainWidget().wrappers[param.name()]
132+
value = None
133+
if wrapper.widget is not None:
134+
value = wrapper.value()
135+
parameters[param.name()] = value
121136

122137
if not param.checkValueIsAcceptable(value):
123138
raise AlgorithmDialogBase.InvalidParameterValue(param, widget)
124139
else:
140+
if self.in_place and param.name() == 'OUTPUT':
141+
parameters[param.name()] = 'memory:'
142+
continue
143+
125144
dest_project = None
126145
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden and \
127146
isinstance(param, (QgsProcessingParameterRasterDestination,
@@ -226,9 +245,12 @@ def on_complete(ok, results):
226245

227246
self.cancelButton().setEnabled(False)
228247

229-
self.finish(ok, results, context, feedback)
248+
if not self.in_place:
249+
self.finish(ok, results, context, feedback)
250+
elif ok:
251+
self.close()
230252

231-
if not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading):
253+
if not self.in_place and not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading):
232254
# Make sure the Log tab is visible before executing the algorithm
233255
self.showLog()
234256

@@ -241,7 +263,10 @@ def on_complete(ok, results):
241263
feedback.progressChanged.connect(self.proxy_progress.setProxyProgress)
242264
self.feedback_dialog = self.createProgressDialog()
243265
self.feedback_dialog.show()
244-
ok, results = execute(self.algorithm(), parameters, context, feedback)
266+
if self.in_place:
267+
ok, results = execute_in_place(self.algorithm(), parameters, context, feedback)
268+
else:
269+
ok, results = execute(self.algorithm(), parameters, context, feedback)
245270
feedback.progressChanged.disconnect()
246271
self.proxy_progress.finalize(ok)
247272
on_complete(ok, results)

‎python/plugins/processing/gui/AlgorithmExecutor.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@
3333
QgsProcessingUtils,
3434
QgsMessageLog,
3535
QgsProcessingException,
36+
QgsProcessingFeatureSourceDefinition,
3637
QgsProcessingParameters)
3738
from processing.gui.Postprocessing import handleAlgorithmResults
3839
from processing.tools import dataobjects
40+
from qgis.utils import iface
3941

4042

4143
def execute(alg, parameters, context=None, feedback=None):
@@ -61,6 +63,40 @@ def execute(alg, parameters, context=None, feedback=None):
6163
return False, {}
6264

6365

66+
def execute_in_place(alg, parameters, context=None, feedback=None):
67+
68+
if feedback is None:
69+
feedback = QgsProcessingFeedback()
70+
if context is None:
71+
context = dataobjects.createContext(feedback)
72+
73+
parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(iface.activeLayer().id(), True)
74+
75+
parameters['OUTPUT'] = 'memory:'
76+
77+
try:
78+
results, ok = alg.run(parameters, context, feedback)
79+
80+
layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
81+
iface.activeLayer().beginEditCommand('Edit features')
82+
iface.activeLayer().deleteFeatures(iface.activeLayer().selectedFeatureIds())
83+
features = []
84+
for f in layer.getFeatures():
85+
features.append(f)
86+
iface.activeLayer().addFeatures(features)
87+
new_selection = [f.id() for f in features]
88+
iface.activeLayer().endEditCommand()
89+
#iface.activeLayer().selectByIds(new_selection)
90+
iface.activeLayer().triggerRepaint()
91+
92+
return ok, results
93+
except QgsProcessingException as e:
94+
QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
95+
if feedback is not None:
96+
feedback.reportError(e.msg)
97+
return False, {}
98+
99+
64100
def executeIterating(alg, parameters, paramToIter, context, feedback):
65101
# Generate all single-feature layers
66102
parameter_definition = alg.parameterDefinition(paramToIter)

0 commit comments

Comments
 (0)
Please sign in to comment.