Skip to content

Commit

Permalink
Set parents and factor out GUI alg executor
Browse files Browse the repository at this point in the history
  • Loading branch information
elpaso authored and nyalldawson committed Nov 30, 2021
1 parent 908ead8 commit bc3e4ca
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 95 deletions.
91 changes: 58 additions & 33 deletions python/plugins/processing/ProcessingPlugin.py
Expand Up @@ -37,14 +37,12 @@
QgsMimeDataUtils)
from qgis.gui import (QgsOptionsWidgetFactory,
QgsCustomDropHandler)
from qgis.PyQt.QtCore import Qt, QItemSelectionModel, QCoreApplication, QDir, QFileInfo
from qgis.PyQt.QtWidgets import QMenu, QAction
from qgis.PyQt.QtCore import QObject, Qt, QItemSelectionModel, QCoreApplication, QDir, QFileInfo, pyqtSlot
from qgis.PyQt.QtWidgets import QWidget, QMenu, QAction
from qgis.PyQt.QtGui import QIcon, QKeySequence
from qgis.utils import iface

from processing.core.Processing import Processing
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
from processing.gui.ProcessingToolbox import ProcessingToolbox
from processing.gui.HistoryDialog import HistoryDialog
from processing.gui.ConfigDialog import ConfigOptionsPage
Expand All @@ -53,8 +51,9 @@
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.AlgorithmLocatorFilter import (AlgorithmLocatorFilter,
InPlaceAlgorithmLocatorFilter, execute_in_place)
from processing.gui.AlgorithmExecutor import execute
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
from processing.modeler.ModelerDialog import ModelerDialog
from processing.tools.system import tempHelpFolder
from processing.tools import dataobjects
Expand Down Expand Up @@ -165,9 +164,10 @@ def createDataItem(self, path, parentItem):
return None


class ProcessingPlugin:
class ProcessingPlugin(QObject):

def __init__(self, iface):
super().__init__()
self.iface = iface
self.options_factory = None
self.drop_handler = None
Expand Down Expand Up @@ -202,6 +202,8 @@ def initGui(self):
self.toolbox.hide()
self.toolbox.visibilityChanged.connect(self.toolboxVisibilityChanged)

self.toolbox.executeWithGui.connect(self.executeProjectModel)

self.resultsDock = ResultsDock()
self.iface.addDockWidget(Qt.RightDockWidgetArea, self.resultsDock)
self.resultsDock.hide()
Expand Down Expand Up @@ -289,16 +291,55 @@ def initGui(self):
self.iface.actionToggleEditing().triggered.connect(partial(self.sync_in_place_button_state, None))
self.sync_in_place_button_state()

self.projectProvider = QgsApplication.instance().processingRegistry().providerById("project")
self.projectProvider.algorithmsLoaded.connect(self.updateProjectModelMenu)
# Sync project models
self.projectModelsMenu = None
self.projectMenuAction = None
self.projectMenuSeparator = None

def executeProjectModel(self, alg_id, as_batch=False):
"""Executes a project model"""
self.projectProvider = QgsApplication.instance().processingRegistry().providerById("project")
self.projectProvider.algorithmsLoaded.connect(self.updateProjectModelMenu)

def updateProjectModelMenu(self):
"""Add projects models to menu"""

if self.projectMenuAction is None:
self.projectModelsMenu = QMenu(self.tr("Models"))
self.projectMenuAction = self.iface.projectMenu().insertMenu(self.iface.projectMenu().children()[-1], self.projectModelsMenu)
self.projectMenuAction.setParent(self.projectModelsMenu)
self.iface.projectMenu().insertSeparator(self.projectMenuAction)

self.projectModelsMenu.clear()

alg = QgsApplication.instance().processingRegistry().createAlgorithmById(alg_id)
for model in self.projectProvider.algorithms():
modelSubMenu = self.projectModelsMenu.addMenu(model.name())
modelSubMenu.setParent(self.projectModelsMenu)
action = QAction(self.tr("Execute…"), modelSubMenu)
action.triggered.connect(partial(self.executeProjectModel, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode))
modelSubMenu.addAction(action)
if model.flags() & QgsProcessingAlgorithm.FlagSupportsBatch:
action = QAction(self.tr("Execute as Batch Process…"), modelSubMenu)
modelSubMenu.addAction(action)
action.triggered.connect(partial(self.executeProjectModel, model.id(), self.projectModelsMenu, self.toolbox.in_place_mode, True))

@pyqtSlot(str, QWidget, bool, bool)
def executeProjectModel(self, alg_id, parent, in_place=False, as_batch=False):
"""Executes a project model with GUI interaction if needed.
:param alg_id: algorithm id
:type alg_id: string
:param parent: parent widget
:type parent: QWidget
:param in_place: in place flag, defaults to False
:type in_place: bool, optional
:param as_batch: execute as batch flag, defaults to False
:type as_batch: bool, optional
"""

config = {}
if in_place:
config['IN_PLACE'] = True

alg = QgsApplication.instance().processingRegistry().createAlgorithmById(alg_id, config)

if alg is not None:

Expand All @@ -313,7 +354,7 @@ def executeProjectModel(self, alg_id, as_batch=False):
return

if as_batch:
dlg = BatchAlgorithmDialog(alg, self.iface.mainWindow())
dlg = BatchAlgorithmDialog(alg, iface.mainWindow())
dlg.setAttribute(Qt.WA_DeleteOnClose)
dlg.show()
dlg.exec_()
Expand All @@ -322,22 +363,22 @@ def executeProjectModel(self, alg_id, as_batch=False):
if hasattr(alg, 'inputParameterName'):
in_place_input_parameter_name = alg.inputParameterName()

if self.toolbox.in_place_mode and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]:
if in_place and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]:
parameters = {}
feedback = MessageBarProgress(algname=alg.displayName())
ok, results = execute_in_place(alg, parameters, feedback=feedback)
if ok:
self.iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName()))
iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName()))
feedback.close()
# MessageBarProgress handles errors
return

if alg.countVisibleParameters() > 0:
dlg = alg.createCustomParametersWidget(self.toolbox)
dlg = alg.createCustomParametersWidget(parent)

if not dlg:
dlg = AlgorithmDialog(alg, self.toolbox.in_place_mode, self.iface.mainWindow())
canvas = self.iface.mapCanvas()
dlg = AlgorithmDialog(alg, in_place, iface.mainWindow())
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
Expand All @@ -355,22 +396,6 @@ def executeProjectModel(self, alg_id, as_batch=False):
handleAlgorithmResults(alg, context, feedback)
feedback.close()

def updateProjectModelMenu(self):
"""Add projects models to menu"""

if self.projectMenuAction is None:
self.projectModelsMenu = QMenu(self.tr("Models"))
self.projectMenuAction = self.iface.projectMenu().insertMenu(self.iface.projectMenu().children()[-1], self.projectModelsMenu)
self.iface.projectMenu().insertSeparator(self.projectMenuAction)

self.projectModelsMenu.clear()

for model in self.projectProvider.algorithms():
modelSubMenu = self.projectModelsMenu.addMenu(model.name())
modelSubMenu.addAction(self.tr("Execute…"), partial(self.executeProjectModel, model.id()))
if model.flags() & QgsProcessingAlgorithm.FlagSupportsBatch:
modelSubMenu.addAction(self.tr("Execute as Batch Process…"), partial(self.executeProjectModel, model.id(), True))

def sync_in_place_button_state(self, layer=None):
"""Synchronise the button state with layer state"""

Expand Down
1 change: 1 addition & 0 deletions python/plugins/processing/gui/AlgorithmExecutor.py
Expand Up @@ -24,6 +24,7 @@
import sys
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (Qgis,
QgsApplication,
QgsFeatureSink,
QgsProcessingFeedback,
QgsProcessingUtils,
Expand Down
69 changes: 7 additions & 62 deletions python/plugins/processing/gui/ProcessingToolbox.py
Expand Up @@ -26,8 +26,8 @@
import warnings

from qgis.PyQt import uic
from qgis.PyQt.QtCore import Qt, QCoreApplication
from qgis.PyQt.QtWidgets import QToolButton, QMenu, QAction
from qgis.PyQt.QtCore import Qt, QCoreApplication, pyqtSignal
from qgis.PyQt.QtWidgets import QWidget, QToolButton, QMenu, QAction
from qgis.utils import iface
from qgis.core import (QgsWkbTypes,
QgsMapLayerType,
Expand All @@ -40,11 +40,8 @@
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.core.ProcessingConfig import ProcessingConfig
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
from processing.gui.EditRenderingStylesDialog import EditRenderingStylesDialog
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.AlgorithmExecutor import execute
from processing.gui.ProviderActions import (ProviderActions,
ProviderContextMenuActions)
from processing.tools import dataobjects
Expand All @@ -67,6 +64,9 @@ class ProcessingToolbox(QgsDockWidget, WIDGET):
TAG_ROLE = Qt.UserRole + 1
TYPE_ROLE = Qt.UserRole + 2

# Trigger algorithm execution
executeWithGui = pyqtSignal(str, QWidget, bool, bool)

def __init__(self):
super(ProcessingToolbox, self).__init__(None)
self.tipWasClosed = False
Expand Down Expand Up @@ -225,62 +225,7 @@ def activateCurrent(self):
self.executeAlgorithm()

def executeAlgorithmAsBatchProcess(self):
alg = self.algorithmTree.selectedAlgorithm().create() if self.algorithmTree.selectedAlgorithm() is not None else None
if alg is not None:
dlg = BatchAlgorithmDialog(alg, iface.mainWindow())
dlg.setAttribute(Qt.WA_DeleteOnClose)
dlg.show()
dlg.exec_()
self.executeWithGui.emit(self.algorithmTree.selectedAlgorithm().id(), self, self.in_place_mode, True)

def executeAlgorithm(self):
config = {}
if self.in_place_mode:
config['IN_PLACE'] = True
alg = self.algorithmTree.selectedAlgorithm().create(config) if self.algorithmTree.selectedAlgorithm() is not None else None
if alg is not None:
ok, message = alg.canExecute()
if not ok:
dlg = MessageDialog()
dlg.setTitle(self.tr('Error executing algorithm'))
dlg.setMessage(
self.tr('<h3>This algorithm cannot '
'be run :-( </h3>\n{0}').format(message))
dlg.exec_()
return

in_place_input_parameter_name = 'INPUT'
if hasattr(alg, 'inputParameterName'):
in_place_input_parameter_name = alg.inputParameterName()

if self.in_place_mode and not [d for d in alg.parameterDefinitions() if d.name() not in (in_place_input_parameter_name, 'OUTPUT')]:
parameters = {}
feedback = MessageBarProgress(algname=alg.displayName())
ok, results = execute_in_place(alg, parameters, feedback=feedback)
if ok:
iface.messageBar().pushSuccess('', self.tr('{algname} completed. %n feature(s) processed.', n=results['__count']).format(algname=alg.displayName()))
feedback.close()
# MessageBarProgress handles errors
return

if alg.countVisibleParameters() > 0:
dlg = alg.createCustomParametersWidget(self)

if not dlg:
dlg = AlgorithmDialog(alg, self.in_place_mode, iface.mainWindow())
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool() != prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)
else:
feedback = MessageBarProgress(algname=alg.displayName())
context = dataobjects.createContext(feedback)
parameters = {}
ret, results = execute(alg, parameters, context, feedback)
handleAlgorithmResults(alg, context, feedback)
feedback.close()
self.executeWithGui.emit(self.algorithmTree.selectedAlgorithm().id(), self, self.in_place_mode, False)

0 comments on commit bc3e4ca

Please sign in to comment.