Skip to content

Commit

Permalink
Added first version of threading interface (by Camilo Polymeris, as p…
Browse files Browse the repository at this point in the history
…art of GSoC 2012)

Fixed #5720. Still have to add refreshing to the model after the change in the element is done.

git-svn-id: http://sextante.googlecode.com/svn/trunk/soft/bindings/qgis-plugin@227 881b9c09-3ef8-f3c2-ec3d-21d735c97f4d
  • Loading branch information
volayaf committed Jun 5, 2012
1 parent cd73169 commit bbefe6d
Show file tree
Hide file tree
Showing 9 changed files with 183 additions and 157 deletions.
9 changes: 6 additions & 3 deletions src/sextante/core/Sextante.py
Expand Up @@ -3,7 +3,7 @@
from sextante.saga.SagaAlgorithmProvider import SagaAlgorithmProvider
from sextante.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider
from sextante.core.QGisLayers import QGisLayers
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor, SilentProgress
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
from sextante.core.SextanteConfig import SextanteConfig
from sextante.core.SextanteLog import SextanteLog
from sextante.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider
Expand Down Expand Up @@ -281,7 +281,8 @@ def runalg(name, *args):
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, alg.getAsCommand())

QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
AlgorithmExecutor.runalg(alg, SilentProgress())
algEx = AlgorithmExecutor(alg)
algEx.start()
QApplication.restoreOverrideCursor()
return alg.getOutputValuesAsDictionary()

Expand Down Expand Up @@ -336,7 +337,9 @@ def runandload(name, *args):
return

QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
ret = AlgorithmExecutor.runalg(alg, SilentProgress())
#~ ret = AlgorithmExecutor.runalg(alg, SilentProgress())
algex = AlgorithmExecutor(alg, SilentProgress())
algex.start()
QApplication.restoreOverrideCursor()
if ret:
SextantePostprocessing.handleAlgorithmResults(alg)
Expand Down
117 changes: 61 additions & 56 deletions src/sextante/gui/AlgorithmExecutor.py
Expand Up @@ -7,71 +7,76 @@
from sextante.gui.SextantePostprocessing import SextantePostprocessing
import traceback

class AlgorithmExecutor:
class AlgorithmExecutor(QThread):
percentageChanged = pyqtSignal(int)
textChanged = pyqtSignal(QString)
cancelled = pyqtSignal()
error = pyqtSignal()
iterated = pyqtSignal(int)
#started & finished inherited from QThread

@staticmethod
def runalg(alg, progress):
'''executes a given algorithm, showing its progress in the progress object passed along.
Return true if everything went OK, false if the algorithm was canceled or there was
any problem and could not be completed'''
def __init__(self, alg, iterParam = None, parent = None):
QThread.__init__(self, parent)
self.algorithm = alg
self.parameterToIterate = iterParam

class Progress:
def __init__(self, algex):
self.algorithmExecutor = algex
def setText(self, text):
self.algorithmExecutor.textChanged.emit(text)
def setPercentage(self, p):
self.algorithmExecutor.percentageChanged.emit(p)
self.progress = Progress(self)
if self.parameterToIterate:
self.run = self.runalgIterating

#generate all single-feature layers
settings = QSettings()
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
layerfile = alg.getParameterValue(self.parameterToIterate)
layer = QGisLayers.getObjectFromUri(layerfile, False)
provider = layer.dataProvider()
allAttrs = provider.attributeIndexes()
provider.select( allAttrs )
feat = QgsFeature()
self.filelist = []
while provider.nextFeature(feat):
output = SextanteUtils.getTempFilename("shp")
self.filelist.append(output)
writer = QgsVectorFileWriter(output, systemEncoding,provider.fields(), provider.geometryType(), provider.crs() )
writer.addFeature(feat)
del writer
else:
self.run = self.runalg

def runalg(self):
try:
alg.execute(progress)
return not alg.canceled
self.algorithm.execute(self.progress)
if self.algorithm.canceled:
self.canceled.emit()
except GeoAlgorithmExecutionException, e :
QMessageBox.critical(None, "Error", e.msg)
return False
except Exception:
QMessageBox.critical(None, "Error", traceback.format_exc())
return False
self.error.emit()
except:
self.error.emit()

@staticmethod
def runalgIterating(alg,paramToIter,progress):
#generate all single-feature layers
settings = QSettings()
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
layerfile = alg.getParameterValue(paramToIter)
layer = QGisLayers.getObjectFromUri(layerfile, False)
provider = layer.dataProvider()
allAttrs = provider.attributeIndexes()
provider.select( allAttrs )
feat = QgsFeature()
filelist = []
def runalgIterating(self):
outputs = {}
while provider.nextFeature(feat):
output = SextanteUtils.getTempFilename("shp")
filelist.append(output)
writer = QgsVectorFileWriter(output, systemEncoding,provider.fields(), provider.geometryType(), provider.crs() )
writer.addFeature(feat)
del writer

#store output values to use them later as basenames for all outputs
for out in alg.outputs:
for out in self.algorithm.outputs:
outputs[out.name] = out.value

#now run all the algorithms
i = 1
for f in filelist:
alg.setParameterValue(paramToIter, f)
for out in alg.outputs:
for f in self.filelist:
self.algorithm.setParameterValue(self.parameterToIterate, f)
for out in self.algorithm.outputs:
filename = outputs[out.name]
if filename:
filename = filename[:filename.rfind(".")] + "_" + str(i) + filename[filename.rfind("."):]
out.value = filename
progress.setText("Executing iteration " + str(i) + "/" + str(len(filelist)) + "...")
progress.setPercentage((i * 100) / len(filelist))
if AlgorithmExecutor.runalg(alg, SilentProgress()):
SextantePostprocessing.handleAlgorithmResults(alg, False)
i+=1
else:
return False;

return True


class SilentProgress():

def setText(self, text):
pass

def setPercentage(self, i):
pass
self.progress.setText("Executing iteration " + str(i) + "/" + str(len(self.filelist)) + "...")
self.progress.setPercentage((i * 100) / len(self.filelist))
self.runalg()
if self.algorithm.canceled:
return
self.iterated.emit(i)
i += 1
13 changes: 4 additions & 9 deletions src/sextante/gui/BatchProcessingDialog.py
Expand Up @@ -12,7 +12,7 @@
from sextante.parameters.ParameterMultipleInput import ParameterMultipleInput
import copy
from sextante.gui.BatchOutputSelectionPanel import BatchOutputSelectionPanel
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor, SilentProgress
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
from sextante.outputs.OutputHTML import OutputHTML
from sextante.core.SextanteResults import SextanteResults
from sextante.gui.ResultsDialog import ResultsDialog
Expand Down Expand Up @@ -99,16 +99,11 @@ def okPressed(self):
self.algs.append(alg)

QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
i=1
self.progress.setMaximum(len(self.algs))
for alg in self.algs:
if AlgorithmExecutor.runalg(alg, SilentProgress()):
self.progress.setValue(i)
self.loadHTMLResults(alg, i)
i+=1
else:
QApplication.restoreOverrideCursor()
return
algEx = AlgorithmExecutor(alg);
algEx.start()

QApplication.restoreOverrideCursor()
QMessageBox.information(self, "Batch processing", "Batch processing successfully completed!")
self.close()
Expand Down
135 changes: 72 additions & 63 deletions src/sextante/gui/ParametersDialog.py
Expand Up @@ -11,11 +11,9 @@
from sextante.parameters.ParameterTableField import ParameterTableField
from sextante.parameters.ParameterTable import ParameterTable
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
from sextante.core.SextanteLog import SextanteLog
from sextante.gui.SextantePostprocessing import SextantePostprocessing
from sextante.parameters.ParameterRange import ParameterRange
from sextante.gui.HTMLViewerDialog import HTMLViewerDialog
from sextante.parameters.ParameterNumber import ParameterNumber

from sextante.gui.ParametersPanel import ParametersPanel
Expand Down Expand Up @@ -52,7 +50,10 @@ def setupUi(self, dialog, alg):
dialog.resize(650, 450)
self.buttonBox = QtGui.QDialogButtonBox()
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
self.buttonBox.setStandardButtons(
QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.Ok)
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)

self.paramTable = ParametersPanel(self.alg, self.dialog)
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidget(self.paramTable)
Expand Down Expand Up @@ -93,8 +94,9 @@ def setupUi(self, dialog, alg):
self.verticalLayout.addWidget(self.progress)
self.verticalLayout.addWidget(self.buttonBox)
dialog.setLayout(self.verticalLayout)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), self.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), self.reject)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.dialog.close)
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).clicked.connect(self.cancel)
QtCore.QMetaObject.connectSlotsByName(dialog)


Expand Down Expand Up @@ -148,67 +150,76 @@ def setParamValue(self, param, widget):
else:
return param.setValue(str(widget.text()))


@pyqtSlot()
def accept(self):
try:
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
if self.setParamValues():
msg = self.alg.checkParameterValuesBeforeExecuting()
if msg:
QMessageBox.critical(self.dialog, "Unable to execute algorithm", msg)
return
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
buttons = self.paramTable.iterateButtons
iterateParam = None
for i in range(len(buttons.values())):
button = buttons.values()[i]
if button.isChecked():
iterateParam = buttons.keys()[i]
break


self.progress.setMaximum(0)
self.progressLabel.setText("Processing algorithm...")
if iterateParam:
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
AlgorithmExecutor.runalgIterating(self.alg, iterateParam, self)
QApplication.restoreOverrideCursor()
else:
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
command = self.alg.getAsCommand()
if command:
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, command)
ret = AlgorithmExecutor.runalg(self.alg, self)
QApplication.restoreOverrideCursor()
if ret:
SextantePostprocessing.handleAlgorithmResults(self.alg, not keepOpen)

self.dialog.executed = True
if not keepOpen:
self.dialog.close()
else:
self.progressLabel.setText("")
self.progress.setValue(0)
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)

else:
QMessageBox.critical(self.dialog, "Unable to execute algorithm", "Wrong or missing parameter values")
#~ try:
if self.setParamValues():
msg = self.alg.checkParameterValuesBeforeExecuting()
if msg:
QMessageBox.critical(self.dialog, "Unable to execute algorithm", msg)
return
except GeoAlgorithmExecutionException, e :
QApplication.restoreOverrideCursor()
QMessageBox.critical(self, "Error",e.msg)
SextanteLog.addToLog(SextanteLog.LOG_ERROR, e.msg)
if not keepOpen:
self.dialog.close()
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
buttons = self.paramTable.iterateButtons
iterateParam = None

for i in range(len(buttons.values())):
button = buttons.values()[i]
if button.isChecked():
iterateParam = buttons.keys()[i]
break

self.progress.setMaximum(0)
self.progressLabel.setText("Processing algorithm...")
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
if iterateParam:
self.algEx = AlgorithmExecutor(self.alg, iterateParam)
else:
self.progressLabel.setText("")
self.progress.setValue(0)
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
command = self.alg.getAsCommand()
if command:
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, command)
self.algEx = AlgorithmExecutor(self.alg)
self.algEx.finished.connect(self.finish)
self.algEx.percentageChanged.connect(self.setPercentage)
self.algEx.textChanged.connect(self.setText)
self.algEx.start()
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(True)
else:
QMessageBox.critical(self.dialog, "Unable to execute algorithm", "Wrong or missing parameter values")

@pyqtSlot()
def finish(self):
self.dialog.executed = True
QApplication.restoreOverrideCursor()

def reject(self):
self.dialog.close()
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)

if not keepOpen:
self.dialog.close()
else:
self.progressLabel.setText("")
self.progress.setValue(0)
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
SextantePostprocessing.handleAlgorithmResults(self.alg, not keepOpen)

#~ except GeoAlgorithmExecutionException, e :
#~ QApplication.restoreOverrideCursor()
#~ QMessageBox.critical(self, "Error",e.msg)
#~ SextanteLog.addToLog(SextanteLog.LOG_ERROR, e.msg)
#~ if not keepOpen:
#~ self.dialog.close()
#~ else:
#~ self.progressLabel.setText("")
#~ self.progress.setValue(0)
#~ self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)

@pyqtSlot()
def cancel(self):
try:
self.algEx.finished.disconnect()
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
except:
pass

def setPercentage(self, i):
if self.progress.maximum() == 0:
Expand All @@ -217,5 +228,3 @@ def setPercentage(self, i):

def setText(self, text):
self.progressLabel.setText(text)


4 changes: 0 additions & 4 deletions src/sextante/modeler/CalculatorModelerAlgorithm

This file was deleted.

4 changes: 4 additions & 0 deletions src/sextante/modeler/ModelerAlgorithm.py
Expand Up @@ -133,6 +133,10 @@ def addParameter(self, param):
self.parameters.append(param)
self.paramPos.append(self.getPositionForParameterItem())

def updateParameter(self, paramIndex, param):
self.parameters[paramIndex] = param
#self.updateModelerView()

def addAlgorithm(self, alg, parametersMap, valuesMap, outputsMap):
self.algs.append(alg)
self.algParameters.append(parametersMap)
Expand Down

0 comments on commit bbefe6d

Please sign in to comment.