Skip to content

Commit 6bf0bfe

Browse files
author
volayaf
committedAug 6, 2012
added field pyculator algorithm
fixed minor issues in algorithm execution and logging added support for multiline strings updated credits in about html page git-svn-id: http://sextante.googlecode.com/svn/trunk/soft/bindings/qgis-plugin@334 881b9c09-3ef8-f3c2-ec3d-21d735c97f4d
1 parent d4a316a commit 6bf0bfe

File tree

8 files changed

+269
-17
lines changed

8 files changed

+269
-17
lines changed
 

‎src/sextante/about/about.htm

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ <h2>SEXTANTE for QGIS</h2>
99
<p>A development by Victor Olaya (volayaf@gmail.com).</p>
1010
<p>Portions of this software contributed by:
1111
<ul>
12-
<li>Michael Nimm (mmqgis algorithms)</li>
12+
<li>Alexander Bruy</li>
1313
<li>Carson Farmer (fTools algorithms)</li>
1414
<li>Julien Malik (Orfeo Toolbox connectors)</li>
15+
<li>Evgeniy Nikulin (Original Field Pyculator code)</li>
16+
<li>Michael Nimm (mmqgis algorithms)</li>
1517
<li>Camilo Polymeris (Threading). Developed as part of Google Summer of Code 2012</li>
1618
</ul>
1719
</p>

‎src/sextante/algs/FieldPyculator.py

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
from sextante.core.GeoAlgorithm import GeoAlgorithm
2+
from sextante.outputs.OutputVector import OutputVector
3+
from sextante.parameters.ParameterVector import ParameterVector
4+
from qgis.core import *
5+
from PyQt4.QtCore import *
6+
from PyQt4.QtGui import *
7+
from sextante.parameters.ParameterString import ParameterString
8+
from sextante.core.QGisLayers import QGisLayers
9+
import os
10+
from PyQt4 import QtGui
11+
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
12+
from sextante.parameters.ParameterBoolean import ParameterBoolean
13+
import sys
14+
15+
16+
class FieldsPyculator(GeoAlgorithm):
17+
18+
INPUT_LAYER = "INPUT_LAYER"
19+
USE_SELECTED = "USE_SELECTED"
20+
FIELD_NAME = "FIELD_NAME"
21+
#USE_GLOBAL = "USE_GLOBAL"
22+
GLOBAL = "GLOBAL"
23+
FORMULA = "FORMULA"
24+
OUTPUT_LAYER ="OUTPUT_LAYER"
25+
RESULT_VAR_NAME = "value"
26+
27+
def getIcon(self):
28+
return QtGui.QIcon(os.path.dirname(__file__) + "/../images/toolbox.png")
29+
30+
def defineCharacteristics(self):
31+
self.name = "Field Pyculator"
32+
self.group = "Algorithms for vector layers"
33+
self.addParameter(ParameterVector(self.INPUT_LAYER, "Input layer", ParameterVector.VECTOR_TYPE_ANY, False))
34+
self.addParameter(ParameterBoolean(self.USE_SELECTED, "Use only selected features", False))
35+
self.addParameter(ParameterString(self.FIELD_NAME, "Result field name", "NewField"))
36+
#self.addParameter(ParameterBoolean(self.USE_GLOBAL, "Use global expression", False))
37+
self.addParameter(ParameterString(self.GLOBAL, "Global expression", multiline = True))
38+
self.addParameter(ParameterString(self.FORMULA, "Formula", "value = ", multiline = True))
39+
self.addOutput(OutputVector(self.OUTPUT_LAYER, "Output layer"))
40+
41+
42+
def processAlgorithm(self, progress):
43+
fieldname = self.getParameterValue(self.FIELD_NAME)
44+
code = self.getParameterValue(self.FORMULA)
45+
globalExpression = self.getParameterValue(self.GLOBAL)
46+
#useGlobal = self.getParameterValue(self.USE_GLOBAL)
47+
useSelected = self.getParameterValue(self.USE_SELECTED)
48+
settings = QSettings()
49+
systemEncoding = settings.value( "/UI/encoding", "System" ).toString()
50+
output = self.getOutputValue(self.OUTPUT_LAYER)
51+
layer = QGisLayers.getObjectFromUri(self.getParameterValue(self.INPUT_LAYER))
52+
vprovider = layer.dataProvider()
53+
allAttrs = vprovider.attributeIndexes()
54+
vprovider.select( allAttrs )
55+
fields = vprovider.fields()
56+
fields[len(fields)] = QgsField(fieldname, QVariant.Double)
57+
writer = QgsVectorFileWriter( output, systemEncoding,fields, vprovider.geometryType(), vprovider.crs() )
58+
outFeat = QgsFeature()
59+
nFeatures = vprovider.featureCount()
60+
nElement = 0
61+
new_ns = {}
62+
63+
#run global code
64+
if globalExpression.strip() != "":
65+
try:
66+
bytecode = compile(globalExpression, '<string>', 'exec')
67+
exec bytecode in new_ns
68+
except:
69+
raise GeoAlgorithmExecutionException("FieldPyculator code execute error\n" +
70+
"Global code block can't be executed!%s \n %s" %
71+
(unicode(sys.exc_info()[0].__name__), unicode(sys.exc_info()[1])))
72+
73+
#replace all fields tags
74+
field_map = vprovider.fields()
75+
for num, field in field_map.iteritems():
76+
field_name = unicode(field.name())
77+
replval = '__attr[' + str(num) + ']'
78+
code = code.replace("<"+field_name+">",replval)
79+
80+
#replace all special vars
81+
code = code.replace('$id','__id')
82+
code = code.replace('$geom','__geom')
83+
need_id = code.find("__id") != -1
84+
need_geom = code.find("__geom") != -1
85+
need_attrs = code.find("__attr") != -1
86+
87+
88+
#compile
89+
try:
90+
bytecode = compile(code, '<string>', 'exec')
91+
except:
92+
raise GeoAlgorithmExecutionException("FieldPyculator code execute error\n"+
93+
"Field code block can't be executed! %s \n %s"
94+
(unicode(sys.exc_info()[0].__name__), unicode(sys.exc_info()[1])))
95+
96+
97+
#run
98+
if not useSelected:
99+
feat = QgsFeature()
100+
if need_attrs:
101+
attr_ind = vprovider.attributeIndexes()
102+
else:
103+
attr_ind = []
104+
vprovider.select(attr_ind, QgsRectangle(), True)
105+
106+
while vprovider.nextFeature(feat):
107+
progress.setPercentage(int((100 * nElement)/nFeatures))
108+
attrMap = feat.attributeMap()
109+
feat_id = feat.id()
110+
111+
#add needed vars
112+
if need_id:
113+
new_ns['__id'] = feat_id
114+
115+
if need_geom:
116+
geom = feat.geometry()
117+
new_ns['__geom'] = geom
118+
119+
if need_attrs:
120+
attr = []
121+
for num,a in attrMap.iteritems():
122+
attr.append(self.Qvar2py(a))
123+
new_ns['__attr'] = attr
124+
125+
#clear old result
126+
if new_ns.has_key(self.RESULT_VAR_NAME):
127+
del new_ns[self.RESULT_VAR_NAME]
128+
129+
130+
#exec
131+
#try:
132+
exec bytecode in new_ns
133+
#except:
134+
# raise e
135+
#===============================================================
136+
# GeoAlgorithmExecutionException("FieldPyculator code execute error\n"+
137+
# "Field code block can't be executed for feature %s\n%s\n%s" %
138+
# (unicode(sys.exc_info()[0].__name__),
139+
# unicode(sys.exc_info()[1]),
140+
# unicode(feat_id)))
141+
#===============================================================
142+
143+
#check result
144+
if not new_ns.has_key(self.RESULT_VAR_NAME):
145+
raise GeoAlgorithmExecutionException("FieldPyculator code execute error\n" +
146+
"Field code block does not return '%s1' variable! Please declare this variable in your code!" %
147+
self.RESULT_VAR_NAME)
148+
149+
150+
#write feature
151+
nElement += 1
152+
outFeat.setGeometry( feat.geometry() )
153+
outFeat.setAttributeMap( attrMap )
154+
outFeat.addAttribute(len(vprovider.fields()), QVariant(new_ns[self.RESULT_VAR_NAME]))
155+
writer.addFeature(outFeat)
156+
157+
else:
158+
features = layer.selectedFeatures()
159+
nFeatures = len(features)
160+
for feat in features:
161+
progress.setPercentage(int((100 * nElement)/nFeatures))
162+
attrMap = feat.attributeMap()
163+
feat_id = feat.id()
164+
165+
#add needed vars
166+
if need_id:
167+
new_ns['__id'] = feat_id
168+
169+
if need_geom:
170+
geom = feat.geometry()
171+
new_ns['__geom'] = geom
172+
173+
if need_attrs:
174+
attrMap = feat.attributeMap()
175+
attr = []
176+
for num,a in attrMap.iteritems():
177+
attr.append(self.Qvar2py(a))
178+
new_ns['__attr'] = attr
179+
180+
#clear old result
181+
if new_ns.has_key(self.RESULT_VAR_NAME):
182+
del new_ns[self.RESULT_VAR_NAME]
183+
184+
#exec
185+
exec bytecode in new_ns
186+
187+
#check result
188+
if not new_ns.has_key(self.RESULT_VAR_NAME):
189+
raise GeoAlgorithmExecutionException("FieldPyculator code execute error\n" +
190+
"Field code block does not return '%s1' variable! Please declare this variable in your code!" %
191+
self.RESULT_VAR_NAME)
192+
193+
#write feature
194+
nElement += 1
195+
outFeat.setGeometry( feat.geometry() )
196+
outFeat.setAttributeMap( attrMap )
197+
outFeat.addAttribute(len(vprovider.fields()), QVariant(new_ns[self.RESULT_VAR_NAME]))
198+
writer.addFeature(outFeat)
199+
200+
del writer
201+
202+
203+
def Qvar2py(self,qv):
204+
if qv.type() == 2:
205+
return qv.toInt()[0]
206+
if qv.type() == 10:
207+
return unicode(qv.toString())
208+
if qv.type() == 6:
209+
return qv.toDouble()[0]
210+
return None
211+
212+
213+
def checkParameterValuesBeforeExecuting(self):
214+
##TODO check that formula is correct and fields exist
215+
pass
216+
217+

‎src/sextante/algs/SextanteAlgorithmProvider.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
from sextante.algs.SaveSelectedFeatures import SaveSelectedFeatures
77
from sextante.algs.Explode import Explode
88
from sextante.algs.AutoincrementalField import AutoincrementalField
9+
from sextante.algs.FieldPyculator import FieldsPyculator
910

1011
class SextanteAlgorithmProvider(AlgorithmProvider):
1112

1213
def __init__(self):
1314
AlgorithmProvider.__init__(self)
1415
self.alglist = [AddTableField(), FieldsCalculator(), SaveSelectedFeatures(),
15-
AutoincrementalField(), Explode()]
16+
AutoincrementalField(), Explode(), FieldsPyculator()]
1617

1718
def initializeSettings(self):
1819
AlgorithmProvider.initializeSettings(self)

‎src/sextante/core/Sextante.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,6 @@ def runAlgorithm(algOrName, onFinish, *args):
287287

288288
msg = alg.checkParameterValuesBeforeExecuting()
289289
if msg:
290-
try:
291-
QMessageBox.critical(None, "Unable to execute algorithm", msg)
292-
return
293-
except:
294290
print ("Unable to execute algorithm\n" + msg)
295291
return
296292

@@ -304,7 +300,8 @@ def runAlgorithm(algOrName, onFinish, *args):
304300
progress.setLabelText("Executing %s..." % alg.name)
305301
def finish():
306302
QApplication.restoreOverrideCursor()
307-
onFinish(alg)
303+
if onFinish is not None:
304+
onFinish(alg)
308305
progress.close()
309306
def error(msg):
310307
QApplication.restoreOverrideCursor()
@@ -323,8 +320,8 @@ def cancel():
323320
algEx.start()
324321
algEx.wait()
325322
else:
326-
UnthreadedAlgorithmExecutor.runalg(alg, SilentProgress())
327-
if onFinish:
323+
ret = UnthreadedAlgorithmExecutor.runalg(alg, SilentProgress())
324+
if onFinish is not None and ret:
328325
onFinish(alg)
329326
QApplication.restoreOverrideCursor()
330327
return alg

‎src/sextante/gui/AlgorithmExecutionDialog.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from sextante.parameters.ParameterRange import ParameterRange
1919
from sextante.parameters.ParameterNumber import ParameterNumber
2020

21-
from sextante.gui.ParametersPanel import ParametersPanel
2221
from sextante.parameters.ParameterFile import ParameterFile
2322
from sextante.parameters.ParameterCrs import ParameterCrs
2423
from sextante.core.SextanteConfig import SextanteConfig
@@ -30,6 +29,7 @@
3029
from sextante.core.WrongHelpFileException import WrongHelpFileException
3130
import os
3231
from sextante.gui.UnthreadedAlgorithmExecutor import UnthreadedAlgorithmExecutor
32+
from sextante.parameters.ParameterString import ParameterString
3333

3434
try:
3535
_fromUtf8 = QtCore.QString.fromUtf8
@@ -161,8 +161,14 @@ def setParamValue(self, param, widget):
161161
return param.setValue(value)
162162
elif isinstance(param, (ParameterNumber, ParameterFile, ParameterCrs, ParameterExtent)):
163163
return param.setValue(widget.getValue())
164+
elif isinstance(param, ParameterString):
165+
if param.multiline:
166+
return param.setValue(unicode(widget.toPlainText()))
167+
else:
168+
return param.setValue(unicode(widget.text()))
169+
164170
else:
165-
return param.setValue(str(widget.text()))
171+
return param.setValue(unicode(widget.text()))
166172

167173
@pyqtSlot()
168174
def accept(self):
@@ -213,6 +219,18 @@ def accept(self):
213219
SextanteLog.addToLog(SextanteLog.LOG_ALGORITHM, command)
214220
if UnthreadedAlgorithmExecutor.runalg(self.alg, self):
215221
self.finish()
222+
else:
223+
QApplication.restoreOverrideCursor()
224+
keepOpen = SextanteConfig.getSetting(SextanteConfig.KEEP_DIALOG_OPEN)
225+
if not keepOpen:
226+
self.close()
227+
else:
228+
self.progressLabel.setText("")
229+
self.progress.setMaximum(100)
230+
self.progress.setValue(0)
231+
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
232+
self.buttonBox.button(QtGui.QDialogButtonBox.Close).setEnabled(True)
233+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
216234
else:
217235
QMessageBox.critical(self, "Unable to execute algorithm", "Wrong or missing parameter values")
218236

@@ -231,7 +249,7 @@ def finish(self):
231249
self.progress.setValue(0)
232250
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
233251
self.buttonBox.button(QtGui.QDialogButtonBox.Close).setEnabled(True)
234-
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
252+
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
235253

236254
@pyqtSlot(str)
237255
def error(self, msg):
@@ -246,6 +264,7 @@ def error(self, msg):
246264
self.progressLabel.setText("")
247265
self.progress.setValue(0)
248266
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
267+
self.buttonBox.button(QtGui.QDialogButtonBox.Close).setEnabled(True)
249268

250269
@pyqtSlot(int)
251270
def iterate(self, i):
@@ -258,17 +277,19 @@ def cancel(self):
258277
self.algEx.finished.disconnect()
259278
self.algEx.terminate()
260279
QApplication.restoreOverrideCursor()
280+
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).setEnabled(True)
281+
self.buttonBox.button(QtGui.QDialogButtonBox.Close).setEnabled(True)
261282
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setEnabled(False)
262283
except:
263284
pass
264285

265286
@pyqtSlot(str)
266287
def setInfo(self, msg, error = False):
267288
if error:
268-
SextanteLog.addToLog(SextanteLog.LOG_ERROR, msg)
289+
#SextanteLog.addToLog(SextanteLog.LOG_ERROR, msg)
269290
self.logText.append('<b>' + msg + '</b>')
270291
else:
271-
SextanteLog.addToLog(SextanteLog.LOG_INFO, msg)
292+
#SextanteLog.addToLog(SextanteLog.LOG_INFO, msg)
272293
self.logText.append(msg)
273294

274295
def setPercentage(self, i):

‎src/sextante/gui/AlgorithmExecutor.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from sextante.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
55
from sextante.core.QGisLayers import QGisLayers
66
from sextante.core.SextanteUtils import SextanteUtils
7+
import sys
78

89
class AlgorithmExecutor(QThread):
910
percentageChanged = pyqtSignal(int)
@@ -55,13 +56,13 @@ def runalg(self):
5556
self.algorithm.execute(self.progress)
5657
except GeoAlgorithmExecutionException,e :
5758
self.error.emit(e.msg)
58-
except BaseException,e:
59+
except Exception,e:
5960
self.error.emit(str(e))
6061
print str(e)
6162
# catch *all* errors, because QGIS tries to handle them in the GUI, which is fatal, this
6263
# being a separate thread.
6364
except:
64-
print "Error executing " + str(self)
65+
self.error.emit("Error executing " + str(self.alg.name) + "\n" + sys.exc_info()[0])
6566

6667
def runalgIterating(self):
6768
try:

‎src/sextante/gui/ParametersPanel.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from sextante.outputs.OutputRaster import OutputRaster
3030
from sextante.outputs.OutputTable import OutputTable
3131
from sextante.outputs.OutputVector import OutputVector
32+
from sextante.parameters.ParameterString import ParameterString
3233

3334
class ParametersPanel(QtGui.QWidget):
3435

@@ -256,6 +257,17 @@ def getWidgetFromParameter(self, param):
256257
item = ExtentSelectionPanel(self.parent, self.alg, param.default)
257258
elif isinstance(param, ParameterCrs):
258259
item = CrsSelectionPanel(param.default)
260+
elif isinstance(param, ParameterString):
261+
if param.multiline:
262+
verticalLayout = QtGui.QVBoxLayout()
263+
verticalLayout.setSizeConstraint(QtGui.QLayout.SetDefaultConstraint)
264+
textEdit = QtGui.QPlainTextEdit()
265+
textEdit.setPlainText(param.default)
266+
verticalLayout.addWidget(textEdit)
267+
item = textEdit
268+
else:
269+
item = QtGui.QLineEdit()
270+
item.setText(str(param.default))
259271
else:
260272
item = QtGui.QLineEdit()
261273
item.setText(str(param.default))

‎src/sextante/parameters/ParameterString.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22

33
class ParameterString(Parameter):
44

5-
def __init__(self, name="", description="", default=""):
5+
def __init__(self, name="", description="", default="", multiline = False):
66
Parameter.__init__(self, name, description)
77
self.default = default
88
self.value = None
9+
self.multiline = multiline
910

1011
def setValue(self, obj):
1112
if obj is None:

0 commit comments

Comments
 (0)
Please sign in to comment.