1
|
|
2
|
|
3
|
"""
|
4
|
***************************************************************************
|
5
|
SagaAlgorithm.py
|
6
|
---------------------
|
7
|
Date : August 2012
|
8
|
Copyright : (C) 2012 by Victor Olaya
|
9
|
Email : volayaf at gmail dot com
|
10
|
***************************************************************************
|
11
|
* *
|
12
|
* This program is free software; you can redistribute it and/or modify *
|
13
|
* it under the terms of the GNU General Public License as published by *
|
14
|
* the Free Software Foundation; either version 2 of the License, or *
|
15
|
* (at your option) any later version. *
|
16
|
* *
|
17
|
***************************************************************************
|
18
|
"""
|
19
|
|
20
|
__author__ = 'Victor Olaya'
|
21
|
__date__ = 'August 2012'
|
22
|
__copyright__ = '(C) 2012, Victor Olaya'
|
23
|
|
24
|
|
25
|
|
26
|
__revision__ = '$Format:%H$'
|
27
|
|
28
|
import os
|
29
|
import importlib
|
30
|
|
31
|
from qgis.core import *
|
32
|
from PyQt4.QtCore import *
|
33
|
from PyQt4.QtGui import *
|
34
|
|
35
|
from processing.core.GeoAlgorithm import GeoAlgorithm
|
36
|
from processing.core.ProcessingConfig import ProcessingConfig
|
37
|
from processing.core.ProcessingLog import ProcessingLog
|
38
|
from processing.core.GeoAlgorithmExecutionException import \
|
39
|
GeoAlgorithmExecutionException
|
40
|
from processing.parameters.ParameterTable import ParameterTable
|
41
|
from processing.parameters.ParameterMultipleInput import ParameterMultipleInput
|
42
|
from processing.parameters.ParameterRaster import ParameterRaster
|
43
|
from processing.parameters.ParameterNumber import ParameterNumber
|
44
|
from processing.parameters.ParameterSelection import ParameterSelection
|
45
|
from processing.parameters.ParameterTableField import ParameterTableField
|
46
|
from processing.parameters.ParameterExtent import ParameterExtent
|
47
|
from processing.parameters.ParameterFixedTable import ParameterFixedTable
|
48
|
from processing.parameters.ParameterVector import ParameterVector
|
49
|
from processing.parameters.ParameterBoolean import ParameterBoolean
|
50
|
from processing.parameters.ParameterFactory import ParameterFactory
|
51
|
from processing.outputs.OutputFactory import OutputFactory
|
52
|
from processing.outputs.OutputTable import OutputTable
|
53
|
from processing.outputs.OutputVector import OutputVector
|
54
|
from processing.outputs.OutputRaster import OutputRaster
|
55
|
from processing.saga.SagaUtils import SagaUtils
|
56
|
from processing.saga.SagaGroupNameDecorator import SagaGroupNameDecorator
|
57
|
from processing.tools import dataobjects
|
58
|
from processing.tools.system import *
|
59
|
|
60
|
sessionExportedLayers = {}
|
61
|
|
62
|
|
63
|
class SagaAlgorithm(GeoAlgorithm):
|
64
|
|
65
|
OUTPUT_EXTENT = 'OUTPUT_EXTENT'
|
66
|
|
67
|
def __init__(self, descriptionfile):
|
68
|
|
69
|
self.resample = True
|
70
|
|
71
|
|
72
|
GeoAlgorithm.__init__(self)
|
73
|
self.descriptionFile = descriptionfile
|
74
|
self.defineCharacteristicsFromFile()
|
75
|
if self.resample:
|
76
|
|
77
|
|
78
|
self.resample = self.setResamplingPolicy()
|
79
|
|
80
|
def getCopy(self):
|
81
|
newone = SagaAlgorithm(self.descriptionFile)
|
82
|
newone.provider = self.provider
|
83
|
return newone
|
84
|
|
85
|
def setResamplingPolicy(self):
|
86
|
count = 0
|
87
|
for param in self.parameters:
|
88
|
if isinstance(param, ParameterRaster):
|
89
|
count += 1
|
90
|
if isinstance(param, ParameterMultipleInput):
|
91
|
if param.datatype == ParameterMultipleInput.TYPE_RASTER:
|
92
|
return True
|
93
|
|
94
|
return count > 1
|
95
|
|
96
|
def getIcon(self):
|
97
|
return QIcon(os.path.dirname(__file__) + '/../images/saga.png')
|
98
|
|
99
|
def defineCharacteristicsFromFile(self):
|
100
|
self.hardcodedStrings = []
|
101
|
lines = open(self.descriptionFile)
|
102
|
line = lines.readline().strip('\n').strip()
|
103
|
self.name = line
|
104
|
if '|' in self.name:
|
105
|
tokens = self.name.split('|')
|
106
|
self.name = tokens[0]
|
107
|
self.cmdname = tokens[1]
|
108
|
else:
|
109
|
self.cmdname = self.name
|
110
|
self.name = self.name[0].upper() + self.name[1:].lower()
|
111
|
line = lines.readline().strip('\n').strip()
|
112
|
self.undecoratedGroup = line
|
113
|
self.group = SagaGroupNameDecorator.getDecoratedName(
|
114
|
self.undecoratedGroup)
|
115
|
while line != '':
|
116
|
line = line.strip('\n').strip()
|
117
|
if line.startswith('Hardcoded'):
|
118
|
self.hardcodedStrings.append(line[len('Harcoded|') + 1:])
|
119
|
elif line.startswith('Parameter'):
|
120
|
self.addParameter(ParameterFactory.getFromString(line))
|
121
|
elif line.startswith('DontResample'):
|
122
|
self.resample = False
|
123
|
elif line.startswith('Extent'):
|
124
|
|
125
|
self.extentParamNames = line[6:].strip().split(' ')
|
126
|
self.addParameter(ParameterExtent(self.OUTPUT_EXTENT,
|
127
|
'Output extent', '0,1,0,1'))
|
128
|
else:
|
129
|
self.addOutput(OutputFactory.getFromString(line))
|
130
|
line = lines.readline().strip('\n').strip()
|
131
|
lines.close()
|
132
|
|
133
|
def calculateResamplingExtent(self):
|
134
|
"""This method calculates the resampling extent, but it might
|
135
|
set self.resample to False if, with the current layers, there
|
136
|
is no need to resample.
|
137
|
"""
|
138
|
|
139
|
auto = ProcessingConfig.getSetting(SagaUtils.SAGA_AUTO_RESAMPLING)
|
140
|
if auto:
|
141
|
first = True
|
142
|
self.inputExtentsCount = 0
|
143
|
for param in self.parameters:
|
144
|
if param.value:
|
145
|
if isinstance(param, ParameterRaster):
|
146
|
if isinstance(param.value, QgsRasterLayer):
|
147
|
layer = param.value
|
148
|
else:
|
149
|
layer = dataobjects.getObjectFromUri(param.value)
|
150
|
self.addToResamplingExtent(layer, first)
|
151
|
first = False
|
152
|
if isinstance(param, ParameterMultipleInput):
|
153
|
if param.datatype \
|
154
|
== ParameterMultipleInput.TYPE_RASTER:
|
155
|
layers = param.value.split(';')
|
156
|
for layername in layers:
|
157
|
layer = dataobjects.getObjectFromUri(layername)
|
158
|
self.addToResamplingExtent(layer, first)
|
159
|
first = False
|
160
|
if self.inputExtentsCount < 2:
|
161
|
self.resample = False
|
162
|
else:
|
163
|
self.xmin = ProcessingConfig.getSetting(
|
164
|
SagaUtils.SAGA_RESAMPLING_REGION_XMIN)
|
165
|
self.xmax = ProcessingConfig.getSetting(
|
166
|
SagaUtils.SAGA_RESAMPLING_REGION_XMAX)
|
167
|
self.ymin = ProcessingConfig.getSetting(
|
168
|
SagaUtils.SAGA_RESAMPLING_REGION_YMIN)
|
169
|
self.ymax = ProcessingConfig.getSetting(
|
170
|
SagaUtils.SAGA_RESAMPLING_REGION_YMAX)
|
171
|
self.cellsize = ProcessingConfig.getSetting(
|
172
|
SagaUtils.SAGA_RESAMPLING_REGION_CELLSIZE)
|
173
|
|
174
|
def addToResamplingExtent(self, layer, first):
|
175
|
if layer is None:
|
176
|
return
|
177
|
if first:
|
178
|
self.inputExtentsCount = 1
|
179
|
self.xmin = layer.extent().xMinimum()
|
180
|
self.xmax = layer.extent().xMaximum()
|
181
|
self.ymin = layer.extent().yMinimum()
|
182
|
self.ymax = layer.extent().yMaximum()
|
183
|
self.cellsize = (layer.extent().xMaximum()
|
184
|
- layer.extent().xMinimum()) / layer.width()
|
185
|
else:
|
186
|
cellsize = (layer.extent().xMaximum() -
|
187
|
layer.extent().xMinimum()) / layer.width()
|
188
|
if self.xmin != layer.extent().xMinimum() or self.xmax \
|
189
|
!= layer.extent().xMaximum() or self.ymin \
|
190
|
!= layer.extent().yMinimum() or self.ymax \
|
191
|
!= layer.extent().yMaximum() or self.cellsize != cellsize:
|
192
|
self.xmin = min(self.xmin, layer.extent().xMinimum())
|
193
|
self.xmax = max(self.xmax, layer.extent().xMaximum())
|
194
|
self.ymin = min(self.ymin, layer.extent().yMinimum())
|
195
|
self.ymax = max(self.ymax, layer.extent().yMaximum())
|
196
|
self.cellsize = max(self.cellsize, cellsize)
|
197
|
self.inputExtentsCount += 1
|
198
|
|
199
|
def processAlgorithm(self, progress):
|
200
|
if isWindows():
|
201
|
path = SagaUtils.sagaPath()
|
202
|
if path == '':
|
203
|
raise GeoAlgorithmExecutionException(
|
204
|
'SAGA folder is not configured.\nPlease configure \
|
205
|
it before running SAGA algorithms.')
|
206
|
commands = list()
|
207
|
self.exportedLayers = {}
|
208
|
|
209
|
self.preProcessInputs()
|
210
|
|
211
|
|
212
|
|
213
|
if self.resample:
|
214
|
self.calculateResamplingExtent()
|
215
|
for param in self.parameters:
|
216
|
if isinstance(param, ParameterRaster):
|
217
|
if param.value is None:
|
218
|
continue
|
219
|
value = param.value
|
220
|
if not value.endswith('sgrd'):
|
221
|
exportCommand = self.exportRasterLayer(value)
|
222
|
if exportCommand is not None:
|
223
|
commands.append(exportCommand)
|
224
|
if self.resample:
|
225
|
commands.append(self.resampleRasterLayer(value))
|
226
|
if isinstance(param, ParameterVector):
|
227
|
if param.value is None:
|
228
|
continue
|
229
|
layer = dataobjects.getObjectFromUri(param.value, False)
|
230
|
if layer:
|
231
|
filename = dataobjects.exportVectorLayer(layer)
|
232
|
self.exportedLayers[param.value] = filename
|
233
|
elif not param.value.endswith('shp'):
|
234
|
raise GeoAlgorithmExecutionException(
|
235
|
'Unsupported file format')
|
236
|
if isinstance(param, ParameterTable):
|
237
|
if param.value is None:
|
238
|
continue
|
239
|
table = dataobjects.getObjectFromUri(param.value, False)
|
240
|
if table:
|
241
|
filename = dataobjects.exportTable(table)
|
242
|
self.exportedLayers[param.value] = filename
|
243
|
elif not param.value.endswith('shp'):
|
244
|
raise GeoAlgorithmExecutionException(
|
245
|
'Unsupported file format')
|
246
|
if isinstance(param, ParameterMultipleInput):
|
247
|
if param.value is None:
|
248
|
continue
|
249
|
layers = param.value.split(';')
|
250
|
if layers is None or len(layers) == 0:
|
251
|
continue
|
252
|
if param.datatype == ParameterMultipleInput.TYPE_RASTER:
|
253
|
for layerfile in layers:
|
254
|
if not layerfile.endswith('sgrd'):
|
255
|
exportCommand = self.exportRasterLayer(layerfile)
|
256
|
if exportCommand is not None:
|
257
|
commands.append(exportCommand)
|
258
|
if self.resample:
|
259
|
commands.append(
|
260
|
self.resampleRasterLayer(layerfile))
|
261
|
elif param.datatype == ParameterMultipleInput.TYPE_VECTOR_ANY:
|
262
|
for layerfile in layers:
|
263
|
layer = dataobjects.getObjectFromUri(layerfile, False)
|
264
|
if layer:
|
265
|
filename = dataobjects.exportVectorLayer(layer)
|
266
|
self.exportedLayers[layerfile] = filename
|
267
|
elif not layerfile.endswith('shp'):
|
268
|
raise GeoAlgorithmExecutionException(
|
269
|
'Unsupported file format')
|
270
|
|
271
|
|
272
|
saga208 = ProcessingConfig.getSetting(SagaUtils.SAGA_208)
|
273
|
if isWindows() or isMac() or not saga208:
|
274
|
command = self.undecoratedGroup + ' "' + self.cmdname + '"'
|
275
|
else:
|
276
|
command = 'lib' + self.undecoratedGroup + ' "' + self.cmdname + '"'
|
277
|
|
278
|
if self.hardcodedStrings:
|
279
|
for s in self.hardcodedStrings:
|
280
|
command += ' ' + s
|
281
|
|
282
|
for param in self.parameters:
|
283
|
if param.value is None:
|
284
|
continue
|
285
|
if isinstance(param, (ParameterRaster, ParameterVector,
|
286
|
ParameterTable)):
|
287
|
value = param.value
|
288
|
if value in self.exportedLayers.keys():
|
289
|
command += ' -' + param.name + ' "' \
|
290
|
+ self.exportedLayers[value] + '"'
|
291
|
else:
|
292
|
command += ' -' + param.name + ' "' + value + '"'
|
293
|
elif isinstance(param, ParameterMultipleInput):
|
294
|
s = param.value
|
295
|
for layer in self.exportedLayers.keys():
|
296
|
s = s.replace(layer, self.exportedLayers[layer])
|
297
|
command += ' -' + param.name + ' "' + s + '"'
|
298
|
elif isinstance(param, ParameterBoolean):
|
299
|
if param.value:
|
300
|
command += ' -' + param.name
|
301
|
elif isinstance(param, ParameterFixedTable):
|
302
|
tempTableFile = getTempFilename('txt')
|
303
|
f = open(tempTableFile, 'w')
|
304
|
f.write('\t'.join([col for col in param.cols]) + '\n')
|
305
|
values = param.value.split(',')
|
306
|
for i in range(0, len(values), 3):
|
307
|
s = values[i] + '\t' + values[i + 1] + '\t' + values[i
|
308
|
+ 2] + '\n'
|
309
|
f.write(s)
|
310
|
f.close()
|
311
|
command += ' -' + param.name + ' "' + tempTableFile + '"'
|
312
|
elif isinstance(param, ParameterExtent):
|
313
|
|
314
|
|
315
|
halfcell = self.getOutputCellsize() / 2
|
316
|
offset = [halfcell, -halfcell, halfcell, -halfcell]
|
317
|
values = param.value.split(',')
|
318
|
for i in range(4):
|
319
|
command += ' -' + self.extentParamNames[i] + ' ' \
|
320
|
+ str(float(values[i]) + offset[i])
|
321
|
elif isinstance(param, (ParameterNumber, ParameterSelection)):
|
322
|
command += ' -' + param.name + ' ' + str(param.value)
|
323
|
else:
|
324
|
command += ' -' + param.name + ' "' + str(param.value) + '"'
|
325
|
|
326
|
for out in self.outputs:
|
327
|
if isinstance(out, OutputRaster):
|
328
|
filename = out.getCompatibleFileName(self)
|
329
|
filename += '.sgrd'
|
330
|
command += ' -' + out.name + ' "' + filename + '"'
|
331
|
if isinstance(out, OutputVector):
|
332
|
filename = out.getCompatibleFileName(self)
|
333
|
command += ' -' + out.name + ' "' + filename + '"'
|
334
|
if isinstance(out, OutputTable):
|
335
|
filename = out.getCompatibleFileName(self)
|
336
|
command += ' -' + out.name + ' "' + filename + '"'
|
337
|
|
338
|
commands.append(command)
|
339
|
|
340
|
|
341
|
optim = ProcessingConfig.getSetting(
|
342
|
SagaUtils.SAGA_IMPORT_EXPORT_OPTIMIZATION)
|
343
|
for out in self.outputs:
|
344
|
if isinstance(out, OutputRaster):
|
345
|
filename = out.getCompatibleFileName(self)
|
346
|
filename2 = filename + '.sgrd'
|
347
|
formatIndex = (4 if not saga208 and isWindows() else 1)
|
348
|
sessionExportedLayers[filename] = filename2
|
349
|
dontExport = True
|
350
|
|
351
|
|
352
|
|
353
|
if self.model is not None and optim:
|
354
|
for subalg in self.model.algOutputs:
|
355
|
if out.name in subalg:
|
356
|
if subalg[out.name] is not None:
|
357
|
dontExport = False
|
358
|
break
|
359
|
if dontExport:
|
360
|
continue
|
361
|
|
362
|
if self.cmdname == 'RGB Composite':
|
363
|
if isWindows() or isMac() or not saga208:
|
364
|
commands.append('io_grid_image 0 -IS_RGB -GRID:"' + filename2
|
365
|
+ '" -FILE:"' + filename
|
366
|
+ '"')
|
367
|
else:
|
368
|
commands.append('libio_grid_image 0 -IS_RGB -GRID:"' + filename2
|
369
|
+ '" -FILE:"' + filename
|
370
|
+ '"')
|
371
|
else:
|
372
|
if isWindows() or isMac() or not saga208:
|
373
|
commands.append('io_gdal 1 -GRIDS "' + filename2
|
374
|
+ '" -FORMAT ' + str(formatIndex)
|
375
|
+ ' -TYPE 0 -FILE "' + filename + '"')
|
376
|
else:
|
377
|
commands.append('libio_gdal 1 -GRIDS "' + filename2
|
378
|
+ '" -FORMAT 1 -TYPE 0 -FILE "' + filename
|
379
|
+ '"')
|
380
|
|
381
|
|
382
|
commands = self.editCommands(commands)
|
383
|
SagaUtils.createSagaBatchJobFileFromSagaCommands(commands)
|
384
|
loglines = []
|
385
|
loglines.append('SAGA execution commands')
|
386
|
for line in commands:
|
387
|
progress.setCommand(line)
|
388
|
loglines.append(line)
|
389
|
if ProcessingConfig.getSetting(SagaUtils.SAGA_LOG_COMMANDS):
|
390
|
ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
|
391
|
SagaUtils.executeSaga(progress)
|
392
|
|
393
|
def preProcessInputs(self):
|
394
|
name = self.commandLineName().replace('.', '_')[len('saga:'):]
|
395
|
try:
|
396
|
module = importlib.import_module('processing.saga.ext.' + name)
|
397
|
except ImportError:
|
398
|
return
|
399
|
if hasattr(module, 'preProcessInputs'):
|
400
|
func = getattr(module, 'preProcessInputs')
|
401
|
func(self)
|
402
|
|
403
|
def editCommands(self, commands):
|
404
|
name = self.commandLineName()[len('saga:'):]
|
405
|
try:
|
406
|
module = importlib.import_module('processing.saga.ext.' + name)
|
407
|
except ImportError:
|
408
|
return commands
|
409
|
if hasattr(module, 'editCommands'):
|
410
|
func = getattr(module, 'editCommands')
|
411
|
return func(commands)
|
412
|
else:
|
413
|
return commands
|
414
|
|
415
|
def getOutputCellsize(self):
|
416
|
"""Tries to guess the cellsize of the output, searching for
|
417
|
a parameter with an appropriate name for it.
|
418
|
"""
|
419
|
|
420
|
cellsize = 0
|
421
|
for param in self.parameters:
|
422
|
if param.value is not None and param.name == 'USER_SIZE':
|
423
|
cellsize = float(param.value)
|
424
|
break
|
425
|
return cellsize
|
426
|
|
427
|
def resampleRasterLayer(self, layer):
|
428
|
"""This is supposed to be run after having exported all raster
|
429
|
layers.
|
430
|
"""
|
431
|
|
432
|
if layer in self.exportedLayers.keys():
|
433
|
inputFilename = self.exportedLayers[layer]
|
434
|
else:
|
435
|
inputFilename = layer
|
436
|
destFilename = getTempFilename('sgrd')
|
437
|
self.exportedLayers[layer] = destFilename
|
438
|
saga208 = ProcessingConfig.getSetting(SagaUtils.SAGA_208)
|
439
|
if isWindows() or isMac() or not saga208:
|
440
|
s = 'grid_tools "Resampling" -INPUT "' + inputFilename \
|
441
|
+ '" -TARGET 0 -SCALE_UP_METHOD 4 -SCALE_DOWN_METHOD 4 -USER_XMIN ' \
|
442
|
+ str(self.xmin) + ' -USER_XMAX ' + str(self.xmax) \
|
443
|
+ ' -USER_YMIN ' + str(self.ymin) + ' -USER_YMAX ' \
|
444
|
+ str(self.ymax) + ' -USER_SIZE ' + str(self.cellsize) \
|
445
|
+ ' -USER_GRID "' + destFilename + '"'
|
446
|
else:
|
447
|
s = 'libgrid_tools "Resampling" -INPUT "' + inputFilename \
|
448
|
+ '" -TARGET 0 -SCALE_UP_METHOD 4 -SCALE_DOWN_METHOD 4 -USER_XMIN ' \
|
449
|
+ str(self.xmin) + ' -USER_XMAX ' + str(self.xmax) \
|
450
|
+ ' -USER_YMIN ' + str(self.ymin) + ' -USER_YMAX ' \
|
451
|
+ str(self.ymax) + ' -USER_SIZE ' + str(self.cellsize) \
|
452
|
+ ' -USER_GRID "' + destFilename + '"'
|
453
|
return s
|
454
|
|
455
|
def exportRasterLayer(self, source):
|
456
|
if source in sessionExportedLayers:
|
457
|
self.exportedLayers[source] = sessionExportedLayers[source]
|
458
|
return None
|
459
|
layer = dataobjects.getObjectFromUri(source, False)
|
460
|
if layer:
|
461
|
filename = str(layer.name())
|
462
|
else:
|
463
|
filename = os.path.basename(source)
|
464
|
validChars = \
|
465
|
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:'
|
466
|
filename = ''.join(c for c in filename if c in validChars)
|
467
|
if len(filename) == 0:
|
468
|
filename = 'layer'
|
469
|
destFilename = getTempFilenameInTempFolder(filename + '.sgrd')
|
470
|
self.exportedLayers[source] = destFilename
|
471
|
sessionExportedLayers[source] = destFilename
|
472
|
saga208 = ProcessingConfig.getSetting(SagaUtils.SAGA_208)
|
473
|
if isWindows() or isMac() or not saga208:
|
474
|
return 'io_gdal 0 -TRANSFORM -INTERPOL 0 -GRIDS "' + destFilename + '" -FILES "' + source \
|
475
|
+ '"'
|
476
|
else:
|
477
|
return 'libio_gdal 0 -GRIDS "' + destFilename + '" -FILES "' \
|
478
|
+ source + '"'
|
479
|
|
480
|
def checkBeforeOpeningParametersDialog(self):
|
481
|
msg = SagaUtils.checkSagaIsInstalled()
|
482
|
if msg is not None:
|
483
|
html = '<p>This algorithm requires SAGA to be run.Unfortunately, \
|
484
|
it seems that SAGA is not installed in your system, or it \
|
485
|
is not correctly configured to be used from QGIS</p>'
|
486
|
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/processing/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with QGIS</p>'
|
487
|
return html
|
488
|
|
489
|
def checkParameterValuesBeforeExecuting(self):
|
490
|
"""We check that there are no multiband layers, which are not
|
491
|
supported by SAGA.
|
492
|
"""
|
493
|
|
494
|
for param in self.parameters:
|
495
|
if isinstance(param, ParameterRaster):
|
496
|
value = param.value
|
497
|
layer = dataobjects.getObjectFromUri(value)
|
498
|
if layer is not None and layer.bandCount() > 1:
|
499
|
return 'Input layer ' + str(layer.name()) \
|
500
|
+ ' has more than one band.\n' \
|
501
|
+ 'Multiband layers are not supported by SAGA'
|
502
|
|
503
|
def helpFile(self):
|
504
|
return os.path.join(os.path.dirname(__file__), 'help',
|
505
|
self.name.replace(' ', '') + '.html')
|
506
|
|
507
|
def getPostProcessingErrorMessage(self, wrongLayers):
|
508
|
html = GeoAlgorithm.getPostProcessingErrorMessage(self, wrongLayers)
|
509
|
msg = SagaUtils.checkSagaIsInstalled(True)
|
510
|
html += '<p>This algorithm requires SAGA to be run. A test to check \
|
511
|
if SAGA is correctly installed and configured in your system \
|
512
|
has been performed, with the following result:</p><ul><i>'
|
513
|
if msg is None:
|
514
|
html += 'SAGA seems to be correctly installed and \
|
515
|
configured</li></ul>'
|
516
|
else:
|
517
|
html += msg + '</i></li></ul>'
|
518
|
html += '<p><a href= "http://docs.qgis.org/2.0/html/en/docs/user_manual/processing/3rdParty.html">Click here</a> to know more about how to install and configure SAGA to be used with QGIS</p>'
|
519
|
|
520
|
return html
|