Skip to content

Commit

Permalink
Messy mockup of feature
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 14, 2018
1 parent 34e29b5 commit 681d44f
Show file tree
Hide file tree
Showing 19 changed files with 301 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Abstract base class for processing algorithms.
FlagRequiresMatchingCrs,
FlagNoThreading,
FlagDisplayNameIsLiteral,
FlagSupportsInPlaceEdits,
FlagDeprecated,
};
typedef QFlags<QgsProcessingAlgorithm::Flag> Flags;
Expand Down Expand Up @@ -853,6 +854,9 @@ algorithm in "chains", avoiding the need for temporary outputs in multi-step mod
Constructor for QgsProcessingFeatureBasedAlgorithm.
%End

virtual QgsProcessingAlgorithm::Flags flags() const;


protected:

virtual void initAlgorithm( const QVariantMap &configuration = QVariantMap() );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,7 @@ the results.
{
FilterToolbox,
FilterModeler,
FilterInPlace,
};
typedef QFlags<QgsProcessingToolboxProxyModel::Filter> Filters;

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

void setInPlaceLayerType( QgsWkbTypes::GeometryType type );

void setFilterString( const QString &filter );
%Docstring
Sets a ``filter`` string, such that only algorithms matching the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ if no algorithm is currently selected.
Sets ``filters`` controlling the view's contents.
%End

void setInPlaceLayerType( QgsWkbTypes::GeometryType type );

public slots:

void setFilterString( const QString &filter );
Expand Down
27 changes: 26 additions & 1 deletion python/plugins/processing/ProcessingPlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
QgsDataItemProvider,
QgsDataProvider,
QgsDataItem,
QgsMapLayer,
QgsMimeDataUtils)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsCustomDropHandler)
Expand All @@ -48,7 +49,8 @@
from processing.gui.HistoryDialog import HistoryDialog
from processing.gui.ConfigDialog import ConfigOptionsPage
from processing.gui.ResultsDock import ResultsDock
from processing.gui.AlgorithmLocatorFilter import AlgorithmLocatorFilter
from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter,
InPlaceAlgorithmLocatorFilter)
from processing.modeler.ModelerDialog import ModelerDialog
from processing.tools.system import tempHelpFolder
from processing.gui.menus import removeMenus, initializeMenus, createMenus
Expand Down Expand Up @@ -168,6 +170,8 @@ def __init__(self, iface):
QgsApplication.dataItemProviderRegistry().addProvider(self.item_provider)
self.locator_filter = AlgorithmLocatorFilter()
iface.registerLocatorFilter(self.locator_filter)
self.edit_features_locator_filter = InPlaceAlgorithmLocatorFilter()
iface.registerLocatorFilter(self.edit_features_locator_filter)
Processing.initialize()

def initGui(self):
Expand Down Expand Up @@ -233,6 +237,14 @@ def initGui(self):
self.optionsAction.triggered.connect(self.openProcessingOptions)
self.toolbox.processingToolbar.addAction(self.optionsAction)

self.editSelectedAction = QAction(
QgsApplication.getThemeIcon("/mActionToggleEditing.svg"),
self.tr('Edit Selected Features'), self.iface.mainWindow())
self.editSelectedAction.setObjectName('editSelectedFeatures')
self.editSelectedAction.setCheckable(True)
self.editSelectedAction.toggled.connect(self.editSelected)
self.toolbox.processingToolbar.addAction(self.editSelectedAction)

menuBar = self.iface.mainWindow().menuBar()
menuBar.insertMenu(
self.iface.firstRightStandardMenu().menuAction(), self.menu)
Expand All @@ -242,6 +254,15 @@ def initGui(self):
initializeMenus()
createMenus()

self.iface.currentLayerChanged.connect(self.layer_changed)

def layer_changed(self, layer):
if layer is None or layer.type() != QgsMapLayer.VectorLayer or not layer.isEditable() or not layer.selectedFeatureCount():
self.editSelectedAction.setChecked(False)
self.editSelectedAction.setEnabled(False)
else:
self.editSelectedAction.setEnabled(True)

def openProcessingOptions(self):
self.iface.showOptionsDialog(self.iface.mainWindow(), currentPage='processingOptions')

Expand Down Expand Up @@ -273,6 +294,7 @@ def unload(self):

self.iface.unregisterOptionsWidgetFactory(self.options_factory)
self.iface.deregisterLocatorFilter(self.locator_filter)
self.iface.deregisterLocatorFilter(self.edit_features_locator_filter)
self.iface.unregisterCustomDropHandler(self.drop_handler)
QgsApplication.dataItemProviderRegistry().removeProvider(self.item_provider)

Expand Down Expand Up @@ -306,3 +328,6 @@ def openHistory(self):

def tr(self, message):
return QCoreApplication.translate('ProcessingPlugin', message)

def editSelected(self, enabled):
self.toolbox.set_in_place_edit_mode(enabled)
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/AddTableField.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from qgis.PyQt.QtCore import QVariant
from qgis.core import (QgsField,
QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingParameterString,
QgsProcessingParameterNumber,
QgsProcessingParameterEnum,
Expand Down Expand Up @@ -57,6 +58,9 @@ def __init__(self):
self.tr('String')]
self.field = None

def flags(self):
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits

def initParameters(self, config=None):
self.addParameter(QgsProcessingParameterString(self.FIELD_NAME,
self.tr('Field name')))
Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/DeleteColumn.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

from qgis.core import (QgsProcessingParameterField,
QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingFeatureSource)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm

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

COLUMNS = 'COLUMN'

def flags(self):
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits

def tags(self):
return self.tr('drop,delete,remove,fields,columns,attributes').split(',')

Expand Down
4 changes: 4 additions & 0 deletions python/plugins/processing/algs/qgis/GeometryByExpression.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
QgsExpression,
QgsGeometry,
QgsProcessing,
QgsProcessingAlgorithm,
QgsProcessingException,
QgsProcessingParameterBoolean,
QgsProcessingParameterEnum,
Expand All @@ -51,6 +52,9 @@ def group(self):
def groupId(self):
return 'vectorgeometry'

def flags(self):
return super().flags() & ~QgsProcessingAlgorithm.FlagSupportsInPlaceEdits

def __init__(self):
super().__init__()
self.geometry_types = [self.tr('Polygon'),
Expand Down
43 changes: 34 additions & 9 deletions python/plugins/processing/gui/AlgorithmDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
from processing.gui.ParametersPanel import ParametersPanel
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
from processing.gui.AlgorithmExecutor import executeIterating, execute
from processing.gui.AlgorithmExecutor import executeIterating, execute, execute_in_place
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.gui.wrappers import WidgetWrapper

Expand All @@ -66,19 +66,25 @@

class AlgorithmDialog(QgsProcessingAlgorithmDialogBase):

def __init__(self, alg):
def __init__(self, alg, in_place=False):
super().__init__()
self.feedback_dialog = None
self.in_place = in_place

self.setAlgorithm(alg)
self.setMainWidget(self.getParametersPanel(alg, self))

self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
self.runAsBatchButton.clicked.connect(self.runAsBatch)
self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole) # reset role to ensure left alignment
if not self.in_place:
self.runAsBatchButton = QPushButton(QCoreApplication.translate("AlgorithmDialog", "Run as Batch Process…"))
self.runAsBatchButton.clicked.connect(self.runAsBatch)
self.buttonBox().addButton(self.runAsBatchButton, QDialogButtonBox.ResetRole) # reset role to ensure left alignment
else:
self.runAsBatchButton = None
self.buttonBox().button(QDialogButtonBox.Ok).setText('Modify Selected Features')
self.buttonBox().button(QDialogButtonBox.Close).setText('Cancel')

def getParametersPanel(self, alg, parent):
return ParametersPanel(parent, alg)
return ParametersPanel(parent, alg, self.in_place)

def runAsBatch(self):
self.close()
Expand Down Expand Up @@ -118,10 +124,23 @@ def getParameterValues(self):

value = wrapper.parameterValue()
parameters[param.name()] = value
if self.in_place and param.name() == 'INPUT':
parameters[param.name()] = iface.activeLayer()
continue

wrapper = self.mainWidget().wrappers[param.name()]
value = None
if wrapper.widget is not None:
value = wrapper.value()
parameters[param.name()] = value

if not param.checkValueIsAcceptable(value):
raise AlgorithmDialogBase.InvalidParameterValue(param, widget)
else:
if self.in_place and param.name() == 'OUTPUT':
parameters[param.name()] = 'memory:'
continue

dest_project = None
if not param.flags() & QgsProcessingParameterDefinition.FlagHidden and \
isinstance(param, (QgsProcessingParameterRasterDestination,
Expand Down Expand Up @@ -226,9 +245,12 @@ def on_complete(ok, results):

self.cancelButton().setEnabled(False)

self.finish(ok, results, context, feedback)
if not self.in_place:
self.finish(ok, results, context, feedback)
elif ok:
self.close()

if not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading):
if not self.in_place and not (self.algorithm().flags() & QgsProcessingAlgorithm.FlagNoThreading):
# Make sure the Log tab is visible before executing the algorithm
self.showLog()

Expand All @@ -241,7 +263,10 @@ def on_complete(ok, results):
feedback.progressChanged.connect(self.proxy_progress.setProxyProgress)
self.feedback_dialog = self.createProgressDialog()
self.feedback_dialog.show()
ok, results = execute(self.algorithm(), parameters, context, feedback)
if self.in_place:
ok, results = execute_in_place(self.algorithm(), parameters, context, feedback)
else:
ok, results = execute(self.algorithm(), parameters, context, feedback)
feedback.progressChanged.disconnect()
self.proxy_progress.finalize(ok)
on_complete(ok, results)
Expand Down
36 changes: 36 additions & 0 deletions python/plugins/processing/gui/AlgorithmExecutor.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@
QgsProcessingUtils,
QgsMessageLog,
QgsProcessingException,
QgsProcessingFeatureSourceDefinition,
QgsProcessingParameters)
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.tools import dataobjects
from qgis.utils import iface


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


def execute_in_place(alg, parameters, context=None, feedback=None):

if feedback is None:
feedback = QgsProcessingFeedback()
if context is None:
context = dataobjects.createContext(feedback)

parameters['INPUT'] = QgsProcessingFeatureSourceDefinition(iface.activeLayer().id(), True)

parameters['OUTPUT'] = 'memory:'

try:
results, ok = alg.run(parameters, context, feedback)

layer = QgsProcessingUtils.mapLayerFromString(results['OUTPUT'], context)
iface.activeLayer().beginEditCommand('Edit features')
iface.activeLayer().deleteFeatures(iface.activeLayer().selectedFeatureIds())
features = []
for f in layer.getFeatures():
features.append(f)
iface.activeLayer().addFeatures(features)
new_selection = [f.id() for f in features]
iface.activeLayer().endEditCommand()
#iface.activeLayer().selectByIds(new_selection)
iface.activeLayer().triggerRepaint()

return ok, results
except QgsProcessingException as e:
QgsMessageLog.logMessage(str(sys.exc_info()[0]), 'Processing', Qgis.Critical)
if feedback is not None:
feedback.reportError(e.msg)
return False, {}


def executeIterating(alg, parameters, paramToIter, context, feedback):
# Generate all single-feature layers
parameter_definition = alg.parameterDefinition(paramToIter)
Expand Down
Loading

0 comments on commit 681d44f

Please sign in to comment.