[processing] added preconfigured algorithms

This commit is contained in:
volaya 2016-04-06 10:50:54 +02:00
parent 9d5df4efb7
commit 297f4669fd
17 changed files with 425 additions and 61 deletions

View File

@ -56,6 +56,8 @@ from processing.algs.r.RAlgorithmProvider import RAlgorithmProvider
from processing.algs.saga.SagaAlgorithmProvider import SagaAlgorithmProvider
from processing.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider
from processing.algs.taudem.TauDEMAlgorithmProvider import TauDEMAlgorithmProvider
from processing.preconfigured.PreconfiguredAlgorithmProvider import PreconfiguredAlgorithmProvider
from processing.tools import dataobjects
@ -138,6 +140,7 @@ class Processing:
Processing.addProvider(Grass7AlgorithmProvider(), updateList=False)
Processing.addProvider(ScriptAlgorithmProvider(), updateList=False)
Processing.addProvider(TauDEMAlgorithmProvider(), updateList=False)
Processing.addProvider(PreconfiguredAlgorithmProvider(), updateList=False)
Processing.addProvider(Processing.modeler, updateList=False)
Processing.modeler.initializeSettings()

View File

@ -74,15 +74,15 @@ class AlgorithmDialog(AlgorithmDialogBase):
self.mainWidget = ParametersPanel(self, alg)
self.setMainWidget()
cornerWidget = QWidget()
self.cornerWidget = QWidget()
layout = QVBoxLayout()
layout.setContentsMargins(0, 0, 0, 5)
self.tabWidget.setStyleSheet("QTabBar::tab { height: 30px; }")
runAsBatchButton = QPushButton(self.tr("Run as batch process..."))
runAsBatchButton.clicked.connect(self.runAsBatch)
layout.addWidget(runAsBatchButton)
cornerWidget.setLayout(layout)
self.tabWidget.setCornerWidget(cornerWidget)
self.runAsBatchButton = QPushButton(self.tr("Run as batch process..."))
self.runAsBatchButton.clicked.connect(self.runAsBatch)
layout.addWidget(self.runAsBatchButton)
self.cornerWidget.setLayout(layout)
self.tabWidget.setCornerWidget(self.cornerWidget)
QgsMapLayerRegistry.instance().layerWasAdded.connect(self.mainWidget.layerAdded)
QgsMapLayerRegistry.instance().layersWillBeRemoved.connect(self.mainWidget.layersWillBeRemoved)

View File

@ -31,8 +31,8 @@ from PyQt.QtCore import QCoreApplication
class ContextAction:
def setData(self, alg, toolbox):
self.alg = alg
def setData(self, itemData, toolbox):
self.itemData = itemData
self.toolbox = toolbox
def updateToolbox(self):

View File

@ -46,11 +46,11 @@ class DeleteScriptAction(ContextAction):
def isEnabled(self):
if self.scriptType == self.SCRIPT_PYTHON:
return isinstance(self.alg, ScriptAlgorithm) and self.alg.allowEdit
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
elif self.scriptType == self.SCRIPT_R:
return isinstance(self.alg, RAlgorithm)
return isinstance(self.itemData, RAlgorithm)
def execute(self, alg):
def execute(self):
reply = QMessageBox.question(None,
self.tr('Confirmation', 'DeleteScriptAction'),
self.tr('Are you sure you want to delete this script?',
@ -58,7 +58,7 @@ class DeleteScriptAction(ContextAction):
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
os.remove(self.alg.descriptionFile)
os.remove(self.itemData.descriptionFile)
if self.scriptType == self.SCRIPT_PYTHON:
self.toolbox.updateProvider('script')
elif self.scriptType == self.SCRIPT_R:

View File

@ -42,12 +42,12 @@ class EditScriptAction(ContextAction):
def isEnabled(self):
if self.scriptType == ScriptEditorDialog.SCRIPT_PYTHON:
return isinstance(self.alg, ScriptAlgorithm) and self.alg.allowEdit
return isinstance(self.itemData, ScriptAlgorithm) and self.itemData.allowEdit
elif self.scriptType == ScriptEditorDialog.SCRIPT_R:
return isinstance(self.alg, RAlgorithm)
return isinstance(self.itemData, RAlgorithm)
def execute(self):
dlg = ScriptEditorDialog(self.scriptType, self.alg)
dlg = ScriptEditorDialog(self.scriptType, self.itemData)
dlg.show()
dlg.exec_()
if dlg.update:

View File

@ -17,6 +17,7 @@
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
@ -32,6 +33,7 @@ from PyQt.QtCore import Qt, QCoreApplication
from PyQt.QtWidgets import QMenu, QAction, QTreeWidgetItem, QLabel, QMessageBox
from qgis.utils import iface
from processing.gui.Postprocessing import handleAlgorithmResults
from processing.core.Processing import Processing
from processing.core.ProcessingLog import ProcessingLog
from processing.core.ProcessingConfig import ProcessingConfig
@ -41,7 +43,8 @@ from processing.gui.AlgorithmDialog import AlgorithmDialog
from processing.gui.BatchAlgorithmDialog import BatchAlgorithmDialog
from processing.gui.EditRenderingStylesDialog import EditRenderingStylesDialog
from processing.gui.ConfigDialog import ConfigDialog
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.AlgorithmExecutor import runalg
pluginPath = os.path.split(os.path.dirname(__file__))[0]
WIDGET, BASE = uic.loadUiType(
@ -194,11 +197,14 @@ class ProcessingToolbox(BASE, WIDGET):
editRenderingStylesAction.triggered.connect(
self.editRenderingStyles)
popupmenu.addAction(editRenderingStylesAction)
if isinstance(item, (TreeAlgorithmItem, TreeActionItem)):
data = item.alg if isinstance(item, TreeAlgorithmItem) else item.action
actions = Processing.contextMenuActions
if len(actions) > 0:
popupmenu.addSeparator()
for action in actions:
action.setData(alg, self)
action.setData(data, self)
if action.isEnabled():
contextMenuAction = QAction(action.name,
self.algorithmTree)
@ -237,24 +243,30 @@ class ProcessingToolbox(BASE, WIDGET):
dlg.exec_()
return
alg = alg.getCopy()
dlg = alg.getCustomParametersDialog()
if not dlg:
dlg = AlgorithmDialog(alg)
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool() != prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)
if dlg.executed:
showRecent = ProcessingConfig.getSetting(
ProcessingConfig.SHOW_RECENT_ALGORITHMS)
if showRecent:
self.addRecentAlgorithms(True)
if (alg.getVisibleParametersCount() + alg.getVisibleOutputsCount()) > 0:
dlg = alg.getCustomParametersDialog()
if not dlg:
dlg = AlgorithmDialog(alg)
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool() != prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)
if dlg.executed:
showRecent = ProcessingConfig.getSetting(
ProcessingConfig.SHOW_RECENT_ALGORITHMS)
if showRecent:
self.addRecentAlgorithms(True)
else:
progress = MessageBarProgress()
runalg(alg, progress)
handleAlgorithmResults(alg, progress)
progress.close()
if isinstance(item, TreeActionItem):
action = item.action
action.setData(self)

View File

@ -32,12 +32,6 @@ from PyQt.QtCore import QCoreApplication
class ToolboxAction:
def __init__(self):
# This should be true if the action should be shown even if
# there are no algorithms in the provider (for instance,
# when it is deactivated
self.showAlways = False
def setData(self, toolbox):
self.toolbox = toolbox

View File

@ -1,11 +1,14 @@
import os
from PyQt.QtWidgets import QAction, QMenu
from PyQt4.QtGui import QIcon
from processing.core.Processing import Processing
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from PyQt.QtWidgets import QAction, QMenu
from processing.gui.MessageDialog import MessageDialog
from processing.gui.AlgorithmDialog import AlgorithmDialog
from qgis.utils import iface
import os
from PyQt4.QtGui import QIcon
from processing.gui.MessageBarProgress import MessageBarProgress
from processing.gui.AlgorithmExecutor import runalg
from processing.gui.Postprocessing import handleAlgorithmResults
algorithmsToolbar = None
menusSettingsGroup = 'Menus'
@ -196,19 +199,26 @@ def _executeAlgorithm(alg):
dlg.exec_()
return
alg = alg.getCopy()
dlg = alg.getCustomParametersDialog()
if not dlg:
dlg = AlgorithmDialog(alg)
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool() != prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)
if (alg.getVisibleParametersCount() + alg.getVisibleOutputsCount()) > 0:
dlg = alg.getCustomParametersDialog()
if not dlg:
dlg = AlgorithmDialog(alg)
canvas = iface.mapCanvas()
prevMapTool = canvas.mapTool()
dlg.show()
dlg.exec_()
if canvas.mapTool() != prevMapTool:
try:
canvas.mapTool().reset()
except:
pass
canvas.setMapTool(prevMapTool)
else:
progress = MessageBarProgress()
runalg(alg, progress)
handleAlgorithmResults(alg, progress)
progress.close()
def getMenu(name, parent):

View File

@ -37,7 +37,7 @@ class DeleteModelAction(ContextAction):
self.name = self.tr('Delete model', 'DeleteModelAction')
def isEnabled(self):
return isinstance(self.alg, ModelerAlgorithm)
return isinstance(self.itemData, ModelerAlgorithm)
def execute(self):
reply = QMessageBox.question(
@ -47,5 +47,5 @@ class DeleteModelAction(ContextAction):
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
os.remove(self.alg.descriptionFile)
os.remove(self.itemData.descriptionFile)
self.toolbox.updateProvider('model')

View File

@ -36,10 +36,10 @@ class EditModelAction(ContextAction):
self.name = self.tr('Edit model', 'EditModelAction')
def isEnabled(self):
return isinstance(self.alg, ModelerAlgorithm)
return isinstance(self.itemData, ModelerAlgorithm)
def execute(self):
dlg = ModelerDialog(self.alg.getCopy())
dlg = ModelerDialog(self.itemData.getCopy())
dlg.exec_()
if dlg.update:
self.toolbox.updateProvider('model')

View File

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
NewPreconfiguredAlgorithmAction.py
---------------------
Date : April 2016
Copyright : (C) 2016 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'April 2016'
__copyright__ = '(C) 2016, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from PyQt4.QtGui import QMessageBox
from processing.gui.ContextAction import ContextAction
from processing.preconfigured.PreconfiguredAlgorithm import PreconfiguredAlgorithm
class DeletePreconfiguredAlgorithmAction(ContextAction):
def __init__(self):
self.name = self.tr('Delete preconfigured algorithm', 'DeletePreconfiguredAlgorithmAction')
def isEnabled(self):
return isinstance(self.itemData, PreconfiguredAlgorithm)
def execute(self):
reply = QMessageBox.question(None,
self.tr('Confirmation', 'DeletePreconfiguredAlgorithmAction'),
self.tr('Are you sure you want to delete this algorithm?',
'DeletePreconfiguredAlgorithmAction'),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.No)
if reply == QMessageBox.Yes:
os.remove(self.itemData.descriptionFile)
self.toolbox.updateProvider('preconfigured')

View File

@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
NewPreconfiguredAlgorithmAction.py
---------------------
Date : April 2016
Copyright : (C) 2016 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'April 2016'
__copyright__ = '(C) 2016, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
from processing.gui.ContextAction import ContextAction
from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.preconfigured.PreconfiguredAlgorithmDialog import PreconfiguredAlgorithmDialog
from processing.preconfigured.PreconfiguredAlgorithm import PreconfiguredAlgorithm
class NewPreconfiguredAlgorithmAction(ContextAction):
def __init__(self):
self.name = self.tr('Create preconfigured algorithm', 'NewPreconfiguredAlgorithmAction')
def isEnabled(self):
return (isinstance(self.itemData, GeoAlgorithm) and
not isinstance(self.itemData, PreconfiguredAlgorithm))
def execute(self):
dlg = PreconfiguredAlgorithmDialog(self.itemData, self.toolbox)
dlg.exec_()

View File

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
PreconfiguredAlgorithmAction.py
---------------------
Date : April 2016
Copyright : (C) 2016 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'April 2016'
__copyright__ = '(C) 2016, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from processing.modeler.ModelerUtils import ModelerUtils
from processing.core.GeoAlgorithm import GeoAlgorithm
import json
class PreconfiguredAlgorithm(GeoAlgorithm):
def __init__(self, descriptionFile):
self.descriptionFile = descriptionFile
with open(self.descriptionFile) as f:
self.description = json.load(f)
GeoAlgorithm.__init__(self)
def getCopy(self):
newone = PreconfiguredAlgorithm(self.descriptionFile)
newone.outputs = []
newone.provider = self.provider
newone.name = self.name
newone.group = self.group
return newone
def commandLineName(self):
return 'preconfigured:' + os.path.splitext(os.path.basename(self.descriptionFile))[0].lower()
def defineCharacteristics(self):
self.name = self.description["name"]
self.group = self.description["group"]
self.canRunInBatchMode = False
self.showInModeler = False
def execute(self, progress):
self.alg = ModelerUtils.getAlgorithm(self.description["algname"]).getCopy()
for name, value in self.description["parameters"].iteritems():
self.alg.setParameterValue(name, value)
for name, value in self.description["outputs"].iteritems():
self.alg.setOutputValue(name, value)
self.alg.execute(progress)
self.outputs = self.alg.outputs

View File

@ -0,0 +1,100 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
AlgorithmDialog.py
---------------------
Date : August 2012
Copyright : (C) 2012 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
import json
from processing.preconfigured.PreconfiguredUtils import algAsDict
from processing.preconfigured.PreconfiguredUtils import preconfiguredAlgorithmsFolder
from processing.gui.AlgorithmDialogBase import AlgorithmDialogBase
from processing.gui.AlgorithmDialog import AlgorithmDialog
from PyQt4.QtGui import QMessageBox, QPalette, QColor, QVBoxLayout, QLabel,\
QLineEdit, QWidget
class PreconfiguredAlgorithmDialog(AlgorithmDialog):
def __init__(self, alg, toolbox):
AlgorithmDialog.__init__(self, alg)
self.toolbox = toolbox
self.cornerWidget.setVisible(False)
self.btnRun.setText(self.tr("OK"))
self.tabWidget.removeTab(1)
self.settingsPanel = SettingsPanel()
self.tabWidget.addTab(self.settingsPanel, "Description")
def accept(self):
try:
self.setParamValues()
msg = self.alg._checkParameterValuesBeforeExecuting()
if msg:
QMessageBox.warning(
self, self.tr('Unable to execute algorithm'), msg)
return
description = algAsDict(self.alg)
description["name"] = self.settingsPanel.txtName.text().strip()
description["group"] = self.settingsPanel.txtGroup.text().strip()
if not (description["name"] and description["group"]):
self.tabWidget.setCurrentIndex(1)
return
validChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:'
filename = ''.join(c for c in description["name"] if c in validChars).lower() + ".json"
filepath = os.path.join(preconfiguredAlgorithmsFolder(), filename)
with open(filepath, "w") as f:
json.dump(description, f)
self.toolbox.updateProvider('preconfigured')
except AlgorithmDialogBase.InvalidParameterValue as e:
try:
self.buttonBox.accepted.connect(lambda:
e.widget.setPalette(QPalette()))
palette = e.widget.palette()
palette.setColor(QPalette.Base, QColor(255, 255, 0))
e.widget.setPalette(palette)
self.lblProgress.setText(
self.tr('<b>Missing parameter value: %s</b>') % e.parameter.description)
return
except:
QMessageBox.critical(self,
self.tr('Unable to execute algorithm'),
self.tr('Wrong or missing parameter values'))
self.close()
class SettingsPanel(QWidget):
def __init__(self):
QWidget.__init__(self)
layout = QVBoxLayout()
labelName = QLabel("Name")
labelGroup = QLabel("Group")
self.txtName = QLineEdit()
self.txtGroup = QLineEdit()
layout.addWidget(labelName)
layout.addWidget(self.txtName)
layout.addWidget(labelGroup)
layout.addWidget(self.txtGroup)
layout.addStretch()
self.setLayout(layout)

View File

@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
PreconfiguredAlgorithmProvider.py
---------------------
Date : April 2016
Copyright : (C) 2016 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = 'Victor Olaya'
__date__ = 'April 2016'
__copyright__ = '(C) 2016, Victor Olaya'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import os
from PyQt.QtGui import QIcon
from processing.preconfigured.PreconfiguredAlgorithm import PreconfiguredAlgorithm
from processing.preconfigured.PreconfiguredUtils import preconfiguredAlgorithmsFolder
from processing.core.AlgorithmProvider import AlgorithmProvider
from processing.preconfigured.NewPreconfiguredAlgorithmAction import NewPreconfiguredAlgorithmAction
from processing.preconfigured.DeletePreconfiguredAlgorithmAction import DeletePreconfiguredAlgorithmAction
class PreconfiguredAlgorithmProvider(AlgorithmProvider):
def __init__(self):
AlgorithmProvider.__init__(self)
self.contextMenuActions = \
[NewPreconfiguredAlgorithmAction(), DeletePreconfiguredAlgorithmAction()]
def _loadAlgorithms(self):
self.algs = []
folder = preconfiguredAlgorithmsFolder()
for path, subdirs, files in os.walk(folder):
for descriptionFile in files:
if descriptionFile.endswith('json'):
fullpath = os.path.join(path, descriptionFile)
alg = PreconfiguredAlgorithm(fullpath)
self.algs.append(alg)
def getIcon(self):
return QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)) , 'images', 'alg.png'))
def getName(self):
return 'preconfigured'
def getDescription(self):
return self.tr('Preconfigured algorithms', 'PreconfiguredAlgorithmProvider')

View File

@ -0,0 +1,18 @@
import os
from processing.tools.system import mkdir, userFolder
def preconfiguredAlgorithmsFolder():
folder = unicode(os.path.join(userFolder(), 'preconfigured'))
mkdir(folder)
return folder
def algAsDict(alg):
params = {}
for param in alg.parameters:
params[param.name] = param.value
outputs = {}
for out in alg.outputs:
outputs[out.name] = out.value
return {"parameters": params, "outputs": outputs, "algname": alg.commandLineName()}