Grass7Algorithm.py

Stefan Blumentrath, 2016-05-22 02:49 AM

Download (25.1 KB)

 
1
# -*- coding: utf-8 -*-
2

    
3
"""
4
***************************************************************************
5
    Grass7Algorithm.py
6
    ---------------------
7
    Date                 : February 2015
8
    Copyright            : (C) 2014-2015 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__ = 'February 2015'
22
__copyright__ = '(C) 2012-2015, Victor Olaya'
23

    
24
# This will get replaced with a git SHA1 when you do a git archive
25

    
26
__revision__ = '$Format:%H$'
27

    
28
import os
29
import time
30
import uuid
31
import importlib
32

    
33
from PyQt4.QtCore import QCoreApplication, QUrl
34
from PyQt4.QtGui import QIcon
35

    
36
from qgis.core import QgsRasterLayer
37
from qgis.utils import iface
38

    
39
from processing.core.GeoAlgorithm import GeoAlgorithm
40
from processing.core.ProcessingConfig import ProcessingConfig
41
from processing.core.ProcessingLog import ProcessingLog
42
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
43

    
44
from processing.core.parameters import getParameterFromString, ParameterVector, ParameterMultipleInput, ParameterExtent, ParameterNumber, ParameterSelection, ParameterRaster, ParameterTable, ParameterBoolean, ParameterString
45
from processing.core.outputs import getOutputFromString, OutputRaster, OutputVector, OutputFile, OutputHTML
46

    
47
from Grass7Utils import Grass7Utils
48

    
49
from processing.tools import dataobjects, system
50

    
51
pluginPath = os.path.normpath(os.path.join(
52
    os.path.split(os.path.dirname(__file__))[0], os.pardir))
53

    
54

    
55
class Grass7Algorithm(GeoAlgorithm):
56

    
57
    GRASS_OUTPUT_TYPE_PARAMETER = 'GRASS_OUTPUT_TYPE_PARAMETER'
58
    GRASS_MIN_AREA_PARAMETER = 'GRASS_MIN_AREA_PARAMETER'
59
    GRASS_SNAP_TOLERANCE_PARAMETER = 'GRASS_SNAP_TOLERANCE_PARAMETER'
60
    GRASS_REGION_EXTENT_PARAMETER = 'GRASS_REGION_PARAMETER'
61
    GRASS_REGION_CELLSIZE_PARAMETER = 'GRASS_REGION_CELLSIZE_PARAMETER'
62
    GRASS_REGION_ALIGN_TO_RESOLUTION = '-a_r.region'
63

    
64
    OUTPUT_TYPES = ['auto', 'point', 'line', 'area']
65

    
66
    def __init__(self, descriptionfile):
67
        GeoAlgorithm.__init__(self)
68
        self.hardcodedStrings = []
69
        self.descriptionFile = descriptionfile
70
        self.defineCharacteristicsFromFile()
71
        self.numExportedLayers = 0
72
        self.uniqueSufix = unicode(uuid.uuid4()).replace('-', '')
73

    
74
        # Use the ext mechanism
75
        name = self.commandLineName().replace('.', '_')[len('grass7:'):]
76
        try:
77
            self.module = importlib.import_module('processing.algs.grass7.ext.' + name)
78
        except ImportError:
79
            self.module = None
80

    
81
    def getCopy(self):
82
        newone = Grass7Algorithm(self.descriptionFile)
83
        newone.provider = self.provider
84
        return newone
85

    
86
    def getIcon(self):
87
        return QIcon(os.path.join(pluginPath, 'images', 'grass.png'))
88

    
89
    def help(self):
90
        localDoc = None
91
        html = self.grass7Name + '.html'
92
        if system.isWindows():
93
            # For MS-Windows, use the configured GRASS7 path
94
            localPath = os.path.join(Grass7Utils.grassPath(), 'docs/html', html)
95
            if os.path.exists(localPath):
96
                localDoc = os.path.abspath(localPath)
97
        elif system.isMac():
98
            # For MacOSX official package
99
            localPath = os.path.join('/Applications/GRASS-7.0.app/Contents/MacOS/docs/html', html)
100
            if os.path.exists(localPath):
101
                localDoc = os.path.abspath(localPath)
102
        else:
103
            # For GNU/Linux distributions
104
            searchPaths = ['/usr/share/doc/grass-doc/html', '/opt/grass/docs/html',
105
                           '/usr/share/doc/grass/docs/html']
106
            for path in searchPaths:
107
                localPath = os.path.join(path, html)
108
                if os.path.exists(localPath):
109
                    localDoc = os.path.abspath(localPath)
110

    
111
        # Found the local documentation
112
        if localDoc:
113
            localDoc = QUrl.fromLocalFile(localDoc).toString()
114
            return False, localDoc
115

    
116
        # Return the URL if local doc is not found
117
        return False, 'http://grass.osgeo.org/grass70/manuals/' + self.grass7Name + '.html'
118

    
119
    def getParameterDescriptions(self):
120
        descs = {}
121
        _, helpfile = self.help()
122
        try:
123
            infile = open(helpfile)
124
            lines = infile.readlines()
125
            for i in range(len(lines)):
126
                if lines[i].startswith('<DT><b>'):
127
                    for param in self.parameters:
128
                        searchLine = '<b>' + param.name + '</b>'
129
                        if searchLine in lines[i]:
130
                            i += 1
131
                            descs[param.name] = (lines[i])[4:-6]
132
                            break
133

    
134
            infile.close()
135
        except Exception:
136
            pass
137
        return descs
138

    
139
    def defineCharacteristicsFromFile(self):
140
        lines = open(self.descriptionFile)
141
        line = lines.readline().strip('\n').strip()
142
        self.grass7Name = line
143
        line = lines.readline().strip('\n').strip()
144
        self.name = line
145
        self.i18n_name = QCoreApplication.translate("GrassAlgorithm", line)
146
        if " - " not in self.name:
147
            self.name = self.grass7Name + " - " + self.name
148
            self.i18n_name = self.grass7Name + " - " + self.i18n_name
149
        line = lines.readline().strip('\n').strip()
150
        self.group = line
151
        self.i18n_group = QCoreApplication.translate("GrassAlgorithm", line)
152
        hasRasterOutput = False
153
        hasVectorInput = False
154
        vectorOutputs = 0
155
        line = lines.readline().strip('\n').strip()
156
        while line != '':
157
            try:
158
                line = line.strip('\n').strip()
159
                if line.startswith('Hardcoded'):
160
                    self.hardcodedStrings.append(line[len('Hardcoded|'):])
161
                elif line.startswith('Parameter'):
162
                    parameter = getParameterFromString(line)
163
                    self.addParameter(parameter)
164
                    if isinstance(parameter, ParameterVector):
165
                        hasVectorInput = True
166
                    if isinstance(parameter, ParameterMultipleInput) \
167
                       and parameter.datatype < 3:
168
                        hasVectorInput = True
169
                elif line.startswith('*Parameter'):
170
                    param = getParameterFromString(line[1:])
171
                    param.isAdvanced = True
172
                    self.addParameter(param)
173
                else:
174
                    output = getOutputFromString(line)
175
                    self.addOutput(output)
176
                    if isinstance(output, OutputRaster):
177
                        hasRasterOutput = True
178
                    elif isinstance(output, OutputVector):
179
                        vectorOutputs += 1
180
                    if isinstance(output, OutputHTML):
181
                        self.addOutput(OutputFile("rawoutput", output.description +
182
                                                  " (raw output)", "txt"))
183
                line = lines.readline().strip('\n').strip()
184
            except Exception as e:
185
                ProcessingLog.addToLog(
186
                    ProcessingLog.LOG_ERROR,
187
                    self.tr('Could not open GRASS GIS 7 algorithm: %s\n%s' % (self.descriptionFile, line)))
188
                raise e
189
        lines.close()
190

    
191
        self.addParameter(ParameterExtent(
192
            self.GRASS_REGION_EXTENT_PARAMETER,
193
            self.tr('GRASS GIS 7 region extent'))
194
        )
195
        if hasRasterOutput:
196
            self.addParameter(ParameterNumber(
197
                self.GRASS_REGION_CELLSIZE_PARAMETER,
198
                self.tr('GRASS GIS 7 region cellsize (leave 0 for default)'),
199
                0, None, 0.0))
200
        if hasVectorInput:
201
            param = ParameterNumber(self.GRASS_SNAP_TOLERANCE_PARAMETER,
202
                                    'v.in.ogr snap tolerance (-1 = no snap)',
203
                                    -1, None, -1.0)
204
            param.isAdvanced = True
205
            self.addParameter(param)
206
            param = ParameterNumber(self.GRASS_MIN_AREA_PARAMETER,
207
                                    'v.in.ogr min area', 0, None, 0.0001)
208
            param.isAdvanced = True
209
            self.addParameter(param)
210
        if vectorOutputs == 1:
211
            param = ParameterSelection(self.GRASS_OUTPUT_TYPE_PARAMETER,
212
                                       'v.out.ogr output type',
213
                                       self.OUTPUT_TYPES)
214
            param.isAdvanced = True
215
            self.addParameter(param)
216

    
217
    def getDefaultCellsize(self):
218
        cellsize = 0
219
        for param in self.parameters:
220
            if param.value:
221
                if isinstance(param, ParameterRaster):
222
                    if isinstance(param.value, QgsRasterLayer):
223
                        layer = param.value
224
                    else:
225
                        layer = dataobjects.getObjectFromUri(param.value)
226
                    cellsize = max(cellsize, (layer.extent().xMaximum()
227
                                              - layer.extent().xMinimum())
228
                                   / layer.width())
229
                elif isinstance(param, ParameterMultipleInput):
230

    
231
                    layers = param.value.split(';')
232
                    for layername in layers:
233
                        layer = dataobjects.getObjectFromUri(layername)
234
                        if isinstance(layer, QgsRasterLayer):
235
                            cellsize = max(cellsize, (
236
                                layer.extent().xMaximum()
237
                                - layer.extent().xMinimum())
238
                                / layer.width()
239
                            )
240

    
241
        if cellsize == 0:
242
            cellsize = 100
243
        return cellsize
244

    
245
    def processAlgorithm(self, progress):
246
        if system.isWindows():
247
            path = Grass7Utils.grassPath()
248
            if path == '':
249
                raise GeoAlgorithmExecutionException(
250
                    self.tr('GRASS GIS 7 folder is not configured. Please '
251
                            'configure it before running GRASS GIS 7 algorithms.'))
252

    
253
        # Create brand new commands lists
254
        self.commands = []
255
        self.outputCommands = []
256
        self.exportedLayers = {}
257

    
258
        # If GRASS session has been created outside of this algorithm then
259
        # get the list of layers loaded in GRASS otherwise start a new
260
        # session
261
        existingSession = Grass7Utils.sessionRunning
262
        if existingSession:
263
            self.exportedLayers = Grass7Utils.getSessionLayers()
264
        else:
265
            Grass7Utils.startGrass7Session()
266

    
267
        # Handle ext functions for inputs/command/outputs
268
        if self.module:
269
            if hasattr(self.module, 'processInputs'):
270
                func = getattr(self.module, 'processInputs')
271
                func(self)
272
            else:
273
                self.processInputs()
274

    
275
            if hasattr(self.module, 'processCommand'):
276
                func = getattr(self.module, 'processCommand')
277
                func(self)
278
            else:
279
                self.processCommand()
280

    
281
            if hasattr(self.module, 'processOutputs'):
282
                func = getattr(self.module, 'processOutputs')
283
                func(self)
284
            else:
285
                self.processOutputs()
286
        else:
287
            self.processInputs()
288
            self.processCommand()
289
            self.processOutputs()
290

    
291
        # Run GRASS
292
        loglines = []
293
        loglines.append(self.tr('GRASS GIS 7 execution commands'))
294
        for line in self.commands:
295
            progress.setCommand(line)
296
            loglines.append(line)
297
        if ProcessingConfig.getSetting(Grass7Utils.GRASS_LOG_COMMANDS):
298
            ProcessingLog.addToLog(ProcessingLog.LOG_INFO, loglines)
299

    
300
        Grass7Utils.executeGrass7(self.commands, progress, self.outputCommands)
301

    
302
        for out in self.outputs:
303
            if isinstance(out, OutputHTML):
304
                with open(self.getOutputFromName("rawoutput").value) as f:
305
                    rawOutput = "".join(f.readlines())
306
                with open(out.value, "w") as f:
307
                    f.write("<pre>%s</pre>" % rawOutput)
308

    
309
        # If the session has been created outside of this algorithm, add
310
        # the new GRASS GIS 7 layers to it otherwise finish the session
311
        if existingSession:
312
            Grass7Utils.addSessionLayers(self.exportedLayers)
313
        else:
314
            Grass7Utils.endGrass7Session()
315

    
316
    def processInputs(self):
317
        """Prepare the GRASS import commands"""
318
        for param in self.parameters:
319
            if isinstance(param, ParameterRaster):
320
                if param.value is None:
321
                    continue
322
                value = param.value
323

    
324
                # Check if the layer hasn't already been exported in, for
325
                # example, previous GRASS calls in this session
326
                if value in self.exportedLayers.keys():
327
                    continue
328
                else:
329
                    self.setSessionProjectionFromLayer(value, self.commands)
330
                    self.commands.append(self.exportRasterLayer(value))
331
            if isinstance(param, ParameterVector):
332
                if param.value is None:
333
                    continue
334
                value = param.value
335
                if value in self.exportedLayers.keys():
336
                    continue
337
                else:
338
                    self.setSessionProjectionFromLayer(value, self.commands)
339
                    self.commands.append(self.exportVectorLayer(value))
340
            if isinstance(param, ParameterTable):
341
                pass
342
            if isinstance(param, ParameterMultipleInput):
343
                if param.value is None:
344
                    continue
345
                layers = param.value.split(';')
346
                if layers is None or len(layers) == 0:
347
                    continue
348
                if param.datatype == ParameterMultipleInput.TYPE_RASTER:
349
                    for layer in layers:
350
                        if layer in self.exportedLayers.keys():
351
                            continue
352
                        else:
353
                            self.setSessionProjectionFromLayer(layer, self.commands)
354
                            self.commands.append(self.exportRasterLayer(layer))
355
                elif param.datatype in [ParameterMultipleInput.TYPE_VECTOR_ANY,
356
                                        ParameterMultipleInput.TYPE_VECTOR_LINE,
357
                                        ParameterMultipleInput.TYPE_VECTOR_POLYGON,
358
                                        ParameterMultipleInput.TYPE_VECTOR_POINT]:
359
                    for layer in layers:
360
                        if layer in self.exportedLayers.keys():
361
                            continue
362
                        else:
363
                            self.setSessionProjectionFromLayer(layer, self.commands)
364
                            self.commands.append(self.exportVectorLayer(layer))
365

    
366
        self.setSessionProjectionFromProject(self.commands)
367

    
368
        region = \
369
            unicode(self.getParameterValue(self.GRASS_REGION_EXTENT_PARAMETER))
370
        regionCoords = region.split(',')
371
        command = 'g.region'
372
        command += ' -a'
373
        command += ' n=' + unicode(regionCoords[3])
374
        command += ' s=' + unicode(regionCoords[2])
375
        command += ' e=' + unicode(regionCoords[1])
376
        command += ' w=' + unicode(regionCoords[0])
377
        cellsize = self.getParameterValue(self.GRASS_REGION_CELLSIZE_PARAMETER)
378
        if cellsize:
379
            command += ' res=' + unicode(cellsize)
380
        else:
381
            command += ' res=' + unicode(self.getDefaultCellsize())
382
        alignToResolution = \
383
            self.getParameterValue(self.GRASS_REGION_ALIGN_TO_RESOLUTION)
384
        if alignToResolution:
385
            command += ' -a'
386
        self.commands.append(command)
387

    
388
    def processCommand(self):
389
        """Prepare the GRASS algorithm command"""
390
        self.commands.append('r.external.out directory={} format=GTiff options="TFW=YES,COMPRESS=LZW"'.format('gdal'))
391
        command = self.grass7Name
392
        command += ' ' + ' '.join(self.hardcodedStrings)
393

    
394
        # Add algorithm command
395
        for param in self.parameters:
396
            if param.value is None or param.value == '':
397
                continue
398
            if param.name in [self.GRASS_REGION_CELLSIZE_PARAMETER, self.GRASS_REGION_EXTENT_PARAMETER, self.GRASS_MIN_AREA_PARAMETER, self.GRASS_SNAP_TOLERANCE_PARAMETER, self.GRASS_OUTPUT_TYPE_PARAMETER, self.GRASS_REGION_ALIGN_TO_RESOLUTION]:
399
                continue
400
            if isinstance(param, (ParameterRaster, ParameterVector)):
401
                value = param.value
402
                if value in self.exportedLayers.keys():
403
                    command += ' ' + param.name + '=' \
404
                        + self.exportedLayers[value]
405
                else:
406
                    command += ' ' + param.name + '=' + value
407
            elif isinstance(param, ParameterMultipleInput):
408
                s = param.value
409
                for layer in self.exportedLayers.keys():
410
                    s = s.replace(layer, self.exportedLayers[layer])
411
                s = s.replace(';', ',')
412
                command += ' ' + param.name + '=' + s
413
            elif isinstance(param, ParameterBoolean):
414
                if param.value:
415
                    command += ' ' + param.name
416
            elif isinstance(param, ParameterSelection):
417
                idx = int(param.value)
418
                command += ' ' + param.name + '=' + unicode(param.options[idx])
419
            elif isinstance(param, ParameterString):
420
                command += ' ' + param.name + '="' + unicode(param.value) + '"'
421
            else:
422
                command += ' ' + param.name + '="' + unicode(param.value) + '"'
423

    
424
        for out in self.outputs:
425
            if isinstance(out, OutputFile):
426
                command += ' > ' + out.value
427
            elif not isinstance(out, OutputHTML):
428
                # We add an output name to make sure it is unique if the session
429
                # uses this algorithm several times.
430
                uniqueOutputName = out.name + self.uniqueSufix
431
                command += ' ' + out.name + '=' + uniqueOutputName
432

    
433
                # Add output file to exported layers, to indicate that
434
                # they are present in GRASS
435
                self.exportedLayers[out.value] = uniqueOutputName
436

    
437
        command += ' --overwrite'
438
        self.commands.append(command)
439

    
440
    def processOutputs(self):
441
        """Prepare the GRASS v.out.ogr commands"""
442
        for out in self.outputs:
443
            if isinstance(out, OutputRaster):
444
                filename = out.value
445

    
446
                grass_path = os.path.join(Grass7Utils.grassDataFolder(),
447
                                         'temp_location', 'PERMANENT', 'gdal')
448

    
449
                # Raster layer output: adjust region to layer before
450
                # exporting
451
                # self.commands.append('g.region raster=' + out.name + self.uniqueSufix)
452
                # self.outputCommands.append('g.region raster=' + out.name
453
                #                            + self.uniqueSufix)
454

    
455
                if self.grass7Name == 'r.statistics':
456
                    # r.statistics saves its results in a non-qgis compatible
457
                    # way. Post-process them with r.mapcalc.
458
                    calcExpression = 'correctedoutput' + self.uniqueSufix
459
                    calcExpression += '=@' + out.name + self.uniqueSufix
460
                    command = 'r.mapcalc expression="' + calcExpression + '"'
461
                    self.commands.append(command)
462
                    self.outputCommands.append(command)
463

    
464
                    grass_map = 'correctedoutput' + self.uniqueSufix + '.tif'
465

    
466
                elif self.grass7Name == 'r.composite':
467
                    grass_map = 'correctedoutput' + self.uniqueSufix + '.tif'
468
                elif self.grass7Name == 'r.horizon':
469
                    grass_map = out.name + self.uniqueSufix + '_0' + '.tif'
470
                else:
471
                    grass_map = out.name + self.uniqueSufix + '.tif'
472

    
473
                src = os.path.join(grass_path, grass_map)
474
                command = 'mv ' + src + ' ' + filename
475

    
476
                self.commands.append(command)
477
                self.outputCommands.append(command)
478

    
479

    
480
            if isinstance(out, OutputVector):
481
                filename = out.value
482
                typeidx = self.getParameterValue(self.GRASS_OUTPUT_TYPE_PARAMETER)
483
                outtype = ('auto' if typeidx
484
                           is None else self.OUTPUT_TYPES[typeidx])
485
                if self.grass7Name == 'r.flow':
486
                    command = 'v.out.ogr type=line layer=0 -s -e input=' + out.name + self.uniqueSufix
487
                elif self.grass7Name == 'v.voronoi':
488
                    if '-l' in self.commands[-1]:
489
                        command = 'v.out.ogr type=line layer=0 -s -e input=' + out.name + self.uniqueSufix
490
                    else:
491
                        command = 'v.out.ogr -s -e input=' + out.name + self.uniqueSufix
492
                        command += ' type=' + outtype
493
                elif self.grass7Name == 'v.sample':
494
                    command = 'v.out.ogr type=point -s -e input=' + out.name + self.uniqueSufix
495
                else:
496
                    command = 'v.out.ogr -s -e input=' + out.name + self.uniqueSufix
497
                    command += ' type=' + outtype
498
                command += ' output="' + os.path.dirname(out.value) + '"'
499
                command += ' format=ESRI_Shapefile'
500
                command += ' output_layer=' + os.path.basename(out.value)[:-4]
501
                command += ' --overwrite'
502
                self.commands.append(command)
503
                self.outputCommands.append(command)
504

    
505
    def exportVectorLayer(self, orgFilename):
506

    
507
        # TODO: improve this. We are now exporting if it is not a shapefile,
508
        # but the functionality of v.in.ogr could be used for this.
509
        # We also export if there is a selection
510
        if not os.path.exists(orgFilename) or not orgFilename.endswith('shp'):
511
            layer = dataobjects.getObjectFromUri(orgFilename, False)
512
            if layer:
513
                filename = dataobjects.exportVectorLayer(layer)
514
        else:
515
            layer = dataobjects.getObjectFromUri(orgFilename, False)
516
            if layer:
517
                useSelection = \
518
                    ProcessingConfig.getSetting(ProcessingConfig.USE_SELECTED)
519
                if useSelection and layer.selectedFeatureCount() != 0:
520
                    filename = dataobjects.exportVectorLayer(layer)
521
                else:
522
                    filename = orgFilename
523
            else:
524
                filename = orgFilename
525
        destFilename = self.getTempFilename()
526
        self.exportedLayers[orgFilename] = destFilename
527
        command = 'v.in.ogr'
528
        min_area = self.getParameterValue(self.GRASS_MIN_AREA_PARAMETER)
529
        command += ' min_area=' + unicode(min_area)
530
        snap = self.getParameterValue(self.GRASS_SNAP_TOLERANCE_PARAMETER)
531
        command += ' snap=' + unicode(snap)
532
        command += ' input="' + os.path.dirname(filename) + '"'
533
        command += ' layer=' + os.path.basename(filename)[:-4]
534
        command += ' output=' + destFilename
535
        command += ' --overwrite -o'
536
        return command
537

    
538
    def setSessionProjectionFromProject(self, commands):
539
        if not Grass7Utils.projectionSet:
540
            proj4 = iface.mapCanvas().mapSettings().destinationCrs().toProj4()
541
            command = 'g.proj'
542
            command += ' -c'
543
            command += ' proj4="' + proj4 + '"'
544
            self.commands.append(command)
545
            Grass7Utils.projectionSet = True
546

    
547
    def setSessionProjectionFromLayer(self, layer, commands):
548
        if not Grass7Utils.projectionSet:
549
            qGisLayer = dataobjects.getObjectFromUri(layer)
550
            if qGisLayer:
551
                proj4 = unicode(qGisLayer.crs().toProj4())
552
                command = 'g.proj'
553
                command += ' -c'
554
                command += ' proj4="' + proj4 + '"'
555
                self.commands.append(command)
556
                Grass7Utils.projectionSet = True
557

    
558
    def exportRasterLayer(self, layer):
559
        destFilename = self.getTempFilename()
560
        self.exportedLayers[layer] = destFilename
561
        command = 'r.external'
562
        command += ' input="' + layer + '"'
563
        command += ' band=1'
564
        command += ' output=' + destFilename
565
        command += ' --overwrite -o'
566
        return command
567

    
568
    def getTempFilename(self):
569
        filename = 'tmp' + unicode(time.time()).replace('.', '') \
570
            + unicode(system.getNumExportedLayers())
571
        return filename
572

    
573
    def commandLineName(self):
574
        return 'grass7:' + self.name[:self.name.find(' ')]
575

    
576
    def checkBeforeOpeningParametersDialog(self):
577
        return Grass7Utils.checkGrass7IsInstalled()
578

    
579
    def checkParameterValuesBeforeExecuting(self):
580
        if self.module:
581
            if hasattr(self.module, 'checkParameterValuesBeforeExecuting'):
582
                func = getattr(self.module, 'checkParameterValuesBeforeExecuting')
583
                return func(self)
584
        return