Skip to content

Commit bbefe6d

Browse files
author
volayaf
committed
Added first version of threading interface (by Camilo Polymeris, as part 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
1 parent cd73169 commit bbefe6d

9 files changed

+183
-157
lines changed

src/sextante/core/Sextante.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from sextante.saga.SagaAlgorithmProvider import SagaAlgorithmProvider
44
from sextante.script.ScriptAlgorithmProvider import ScriptAlgorithmProvider
55
from sextante.core.QGisLayers import QGisLayers
6-
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor, SilentProgress
6+
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
77
from sextante.core.SextanteConfig import SextanteConfig
88
from sextante.core.SextanteLog import SextanteLog
99
from sextante.modeler.ModelerAlgorithmProvider import ModelerAlgorithmProvider
@@ -281,7 +281,8 @@ def runalg(name, *args):
281281
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, alg.getAsCommand())
282282

283283
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
284-
AlgorithmExecutor.runalg(alg, SilentProgress())
284+
algEx = AlgorithmExecutor(alg)
285+
algEx.start()
285286
QApplication.restoreOverrideCursor()
286287
return alg.getOutputValuesAsDictionary()
287288

@@ -336,7 +337,9 @@ def runandload(name, *args):
336337
return
337338

338339
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
339-
ret = AlgorithmExecutor.runalg(alg, SilentProgress())
340+
#~ ret = AlgorithmExecutor.runalg(alg, SilentProgress())
341+
algex = AlgorithmExecutor(alg, SilentProgress())
342+
algex.start()
340343
QApplication.restoreOverrideCursor()
341344
if ret:
342345
SextantePostprocessing.handleAlgorithmResults(alg)

src/sextante/gui/AlgorithmExecutor.py

Lines changed: 61 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,71 +7,76 @@
77
from sextante.gui.SextantePostprocessing import SextantePostprocessing
88
import traceback
99

10-
class AlgorithmExecutor:
10+
class AlgorithmExecutor(QThread):
11+
percentageChanged = pyqtSignal(int)
12+
textChanged = pyqtSignal(QString)
13+
cancelled = pyqtSignal()
14+
error = pyqtSignal()
15+
iterated = pyqtSignal(int)
16+
#started & finished inherited from QThread
1117

12-
@staticmethod
13-
def runalg(alg, progress):
14-
'''executes a given algorithm, showing its progress in the progress object passed along.
15-
Return true if everything went OK, false if the algorithm was canceled or there was
16-
any problem and could not be completed'''
18+
def __init__(self, alg, iterParam = None, parent = None):
19+
QThread.__init__(self, parent)
20+
self.algorithm = alg
21+
self.parameterToIterate = iterParam
22+
23+
class Progress:
24+
def __init__(self, algex):
25+
self.algorithmExecutor = algex
26+
def setText(self, text):
27+
self.algorithmExecutor.textChanged.emit(text)
28+
def setPercentage(self, p):
29+
self.algorithmExecutor.percentageChanged.emit(p)
30+
self.progress = Progress(self)
31+
if self.parameterToIterate:
32+
self.run = self.runalgIterating
33+
34+
#generate all single-feature layers
35+
settings = QSettings()
36+
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
37+
layerfile = alg.getParameterValue(self.parameterToIterate)
38+
layer = QGisLayers.getObjectFromUri(layerfile, False)
39+
provider = layer.dataProvider()
40+
allAttrs = provider.attributeIndexes()
41+
provider.select( allAttrs )
42+
feat = QgsFeature()
43+
self.filelist = []
44+
while provider.nextFeature(feat):
45+
output = SextanteUtils.getTempFilename("shp")
46+
self.filelist.append(output)
47+
writer = QgsVectorFileWriter(output, systemEncoding,provider.fields(), provider.geometryType(), provider.crs() )
48+
writer.addFeature(feat)
49+
del writer
50+
else:
51+
self.run = self.runalg
52+
53+
def runalg(self):
1754
try:
18-
alg.execute(progress)
19-
return not alg.canceled
55+
self.algorithm.execute(self.progress)
56+
if self.algorithm.canceled:
57+
self.canceled.emit()
2058
except GeoAlgorithmExecutionException, e :
21-
QMessageBox.critical(None, "Error", e.msg)
22-
return False
23-
except Exception:
24-
QMessageBox.critical(None, "Error", traceback.format_exc())
25-
return False
59+
self.error.emit()
60+
except:
61+
self.error.emit()
2662

27-
@staticmethod
28-
def runalgIterating(alg,paramToIter,progress):
29-
#generate all single-feature layers
30-
settings = QSettings()
31-
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
32-
layerfile = alg.getParameterValue(paramToIter)
33-
layer = QGisLayers.getObjectFromUri(layerfile, False)
34-
provider = layer.dataProvider()
35-
allAttrs = provider.attributeIndexes()
36-
provider.select( allAttrs )
37-
feat = QgsFeature()
38-
filelist = []
63+
def runalgIterating(self):
3964
outputs = {}
40-
while provider.nextFeature(feat):
41-
output = SextanteUtils.getTempFilename("shp")
42-
filelist.append(output)
43-
writer = QgsVectorFileWriter(output, systemEncoding,provider.fields(), provider.geometryType(), provider.crs() )
44-
writer.addFeature(feat)
45-
del writer
46-
4765
#store output values to use them later as basenames for all outputs
48-
for out in alg.outputs:
66+
for out in self.algorithm.outputs:
4967
outputs[out.name] = out.value
50-
51-
#now run all the algorithms
5268
i = 1
53-
for f in filelist:
54-
alg.setParameterValue(paramToIter, f)
55-
for out in alg.outputs:
69+
for f in self.filelist:
70+
self.algorithm.setParameterValue(self.parameterToIterate, f)
71+
for out in self.algorithm.outputs:
5672
filename = outputs[out.name]
5773
if filename:
5874
filename = filename[:filename.rfind(".")] + "_" + str(i) + filename[filename.rfind("."):]
5975
out.value = filename
60-
progress.setText("Executing iteration " + str(i) + "/" + str(len(filelist)) + "...")
61-
progress.setPercentage((i * 100) / len(filelist))
62-
if AlgorithmExecutor.runalg(alg, SilentProgress()):
63-
SextantePostprocessing.handleAlgorithmResults(alg, False)
64-
i+=1
65-
else:
66-
return False;
67-
68-
return True
69-
70-
71-
class SilentProgress():
72-
73-
def setText(self, text):
74-
pass
75-
76-
def setPercentage(self, i):
77-
pass
76+
self.progress.setText("Executing iteration " + str(i) + "/" + str(len(self.filelist)) + "...")
77+
self.progress.setPercentage((i * 100) / len(self.filelist))
78+
self.runalg()
79+
if self.algorithm.canceled:
80+
return
81+
self.iterated.emit(i)
82+
i += 1

src/sextante/gui/BatchProcessingDialog.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from sextante.parameters.ParameterMultipleInput import ParameterMultipleInput
1313
import copy
1414
from sextante.gui.BatchOutputSelectionPanel import BatchOutputSelectionPanel
15-
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor, SilentProgress
15+
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
1616
from sextante.outputs.OutputHTML import OutputHTML
1717
from sextante.core.SextanteResults import SextanteResults
1818
from sextante.gui.ResultsDialog import ResultsDialog
@@ -99,16 +99,11 @@ def okPressed(self):
9999
self.algs.append(alg)
100100

101101
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
102-
i=1
103102
self.progress.setMaximum(len(self.algs))
104103
for alg in self.algs:
105-
if AlgorithmExecutor.runalg(alg, SilentProgress()):
106-
self.progress.setValue(i)
107-
self.loadHTMLResults(alg, i)
108-
i+=1
109-
else:
110-
QApplication.restoreOverrideCursor()
111-
return
104+
algEx = AlgorithmExecutor(alg);
105+
algEx.start()
106+
112107
QApplication.restoreOverrideCursor()
113108
QMessageBox.information(self, "Batch processing", "Batch processing successfully completed!")
114109
self.close()

src/sextante/gui/ParametersDialog.py

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111
from sextante.parameters.ParameterTableField import ParameterTableField
1212
from sextante.parameters.ParameterTable import ParameterTable
1313
from sextante.gui.AlgorithmExecutor import AlgorithmExecutor
14-
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
1514
from sextante.core.SextanteLog import SextanteLog
1615
from sextante.gui.SextantePostprocessing import SextantePostprocessing
1716
from sextante.parameters.ParameterRange import ParameterRange
18-
from sextante.gui.HTMLViewerDialog import HTMLViewerDialog
1917
from sextante.parameters.ParameterNumber import ParameterNumber
2018

2119
from sextante.gui.ParametersPanel import ParametersPanel
@@ -52,7 +50,10 @@ def setupUi(self, dialog, alg):
5250
dialog.resize(650, 450)
5351
self.buttonBox = QtGui.QDialogButtonBox()
5452
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
55-
self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
53+
self.buttonBox.setStandardButtons(
54+
QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Close|QtGui.QDialogButtonBox.Ok)
55+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
56+
5657
self.paramTable = ParametersPanel(self.alg, self.dialog)
5758
self.scrollArea = QtGui.QScrollArea()
5859
self.scrollArea.setWidget(self.paramTable)
@@ -93,8 +94,9 @@ def setupUi(self, dialog, alg):
9394
self.verticalLayout.addWidget(self.progress)
9495
self.verticalLayout.addWidget(self.buttonBox)
9596
dialog.setLayout(self.verticalLayout)
96-
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), self.accept)
97-
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), self.reject)
97+
self.buttonBox.accepted.connect(self.accept)
98+
self.buttonBox.rejected.connect(self.dialog.close)
99+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).clicked.connect(self.cancel)
98100
QtCore.QMetaObject.connectSlotsByName(dialog)
99101

100102

@@ -148,67 +150,76 @@ def setParamValue(self, param, widget):
148150
else:
149151
return param.setValue(str(widget.text()))
150152

151-
153+
@pyqtSlot()
152154
def accept(self):
153-
try:
154-
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
155-
if self.setParamValues():
156-
msg = self.alg.checkParameterValuesBeforeExecuting()
157-
if msg:
158-
QMessageBox.critical(self.dialog, "Unable to execute algorithm", msg)
159-
return
160-
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
161-
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
162-
buttons = self.paramTable.iterateButtons
163-
iterateParam = None
164-
for i in range(len(buttons.values())):
165-
button = buttons.values()[i]
166-
if button.isChecked():
167-
iterateParam = buttons.keys()[i]
168-
break
169-
170-
171-
self.progress.setMaximum(0)
172-
self.progressLabel.setText("Processing algorithm...")
173-
if iterateParam:
174-
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
175-
AlgorithmExecutor.runalgIterating(self.alg, iterateParam, self)
176-
QApplication.restoreOverrideCursor()
177-
else:
178-
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
179-
command = self.alg.getAsCommand()
180-
if command:
181-
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, command)
182-
ret = AlgorithmExecutor.runalg(self.alg, self)
183-
QApplication.restoreOverrideCursor()
184-
if ret:
185-
SextantePostprocessing.handleAlgorithmResults(self.alg, not keepOpen)
186-
187-
self.dialog.executed = True
188-
if not keepOpen:
189-
self.dialog.close()
190-
else:
191-
self.progressLabel.setText("")
192-
self.progress.setValue(0)
193-
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
194-
195-
else:
196-
QMessageBox.critical(self.dialog, "Unable to execute algorithm", "Wrong or missing parameter values")
155+
#~ try:
156+
if self.setParamValues():
157+
msg = self.alg.checkParameterValuesBeforeExecuting()
158+
if msg:
159+
QMessageBox.critical(self.dialog, "Unable to execute algorithm", msg)
197160
return
198-
except GeoAlgorithmExecutionException, e :
199-
QApplication.restoreOverrideCursor()
200-
QMessageBox.critical(self, "Error",e.msg)
201-
SextanteLog.addToLog(SextanteLog.LOG_ERROR, e.msg)
202-
if not keepOpen:
203-
self.dialog.close()
161+
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(False)
162+
buttons = self.paramTable.iterateButtons
163+
iterateParam = None
164+
165+
for i in range(len(buttons.values())):
166+
button = buttons.values()[i]
167+
if button.isChecked():
168+
iterateParam = buttons.keys()[i]
169+
break
170+
171+
self.progress.setMaximum(0)
172+
self.progressLabel.setText("Processing algorithm...")
173+
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
174+
if iterateParam:
175+
self.algEx = AlgorithmExecutor(self.alg, iterateParam)
204176
else:
205-
self.progressLabel.setText("")
206-
self.progress.setValue(0)
207-
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
177+
command = self.alg.getAsCommand()
178+
if command:
179+
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, command)
180+
self.algEx = AlgorithmExecutor(self.alg)
181+
self.algEx.finished.connect(self.finish)
182+
self.algEx.percentageChanged.connect(self.setPercentage)
183+
self.algEx.textChanged.connect(self.setText)
184+
self.algEx.start()
185+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(True)
186+
else:
187+
QMessageBox.critical(self.dialog, "Unable to execute algorithm", "Wrong or missing parameter values")
208188

189+
@pyqtSlot()
190+
def finish(self):
191+
self.dialog.executed = True
192+
QApplication.restoreOverrideCursor()
209193

210-
def reject(self):
211-
self.dialog.close()
194+
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
195+
196+
if not keepOpen:
197+
self.dialog.close()
198+
else:
199+
self.progressLabel.setText("")
200+
self.progress.setValue(0)
201+
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
202+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
203+
SextantePostprocessing.handleAlgorithmResults(self.alg, not keepOpen)
204+
205+
#~ except GeoAlgorithmExecutionException, e :
206+
#~ QApplication.restoreOverrideCursor()
207+
#~ QMessageBox.critical(self, "Error",e.msg)
208+
#~ SextanteLog.addToLog(SextanteLog.LOG_ERROR, e.msg)
209+
#~ if not keepOpen:
210+
#~ self.dialog.close()
211+
#~ else:
212+
#~ self.progressLabel.setText("")
213+
#~ self.progress.setValue(0)
214+
#~ self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
215+
216+
@pyqtSlot()
217+
def cancel(self):
218+
try:
219+
self.algEx.finished.disconnect()
220+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
221+
except:
222+
pass
212223

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

218229
def setText(self, text):
219230
self.progressLabel.setText(text)
220-
221-

src/sextante/modeler/CalculatorModelerAlgorithm

Lines changed: 0 additions & 4 deletions
This file was deleted.

src/sextante/modeler/ModelerAlgorithm.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,10 @@ def addParameter(self, param):
133133
self.parameters.append(param)
134134
self.paramPos.append(self.getPositionForParameterItem())
135135

136+
def updateParameter(self, paramIndex, param):
137+
self.parameters[paramIndex] = param
138+
#self.updateModelerView()
139+
136140
def addAlgorithm(self, alg, parametersMap, valuesMap, outputsMap):
137141
self.algs.append(alg)
138142
self.algParameters.append(parametersMap)

0 commit comments

Comments
 (0)