QGIS/python/plugins/grassprovider/grass_provider.py
2024-11-29 15:38:02 +01:00

229 lines
8.6 KiB
Python

"""
***************************************************************************
grass_provider.py
---------------------
Date : April 2014
Copyright : (C) 2014 by Victor Olaya
Email : volayaf at gmail dot com
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************
"""
__author__ = "Victor Olaya"
__date__ = "April 2014"
__copyright__ = "(C) 2014, Victor Olaya"
import json
from typing import List
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (
Qgis,
QgsApplication,
QgsProcessingAlgorithm,
QgsProcessingProvider,
QgsVectorFileWriter,
QgsMessageLog,
QgsRuntimeProfiler,
)
from processing.core.ProcessingConfig import ProcessingConfig, Setting
from grassprovider.grass_utils import GrassUtils
from grassprovider.grass_algorithm import GrassAlgorithm
class GrassProvider(QgsProcessingProvider):
def __init__(self):
super().__init__()
def load(self):
with QgsRuntimeProfiler.profile("Grass Provider"):
ProcessingConfig.settingIcons[self.name()] = self.icon()
ProcessingConfig.addSetting(
Setting(
self.name(),
GrassUtils.GRASS_LOG_COMMANDS,
self.tr("Log execution commands"),
False,
)
)
ProcessingConfig.addSetting(
Setting(
self.name(),
GrassUtils.GRASS_LOG_CONSOLE,
self.tr("Log console output"),
False,
)
)
ProcessingConfig.addSetting(
Setting(
self.name(),
GrassUtils.GRASS_HELP_URL,
self.tr("Location of GRASS docs"),
"",
)
)
# Add settings for using r.external/v.external instead of r.in.gdal/v.in.ogr
# but set them to False by default because the {r,v}.external implementations
# have some bugs on windows + there are algorithms that can't be used with
# external data (need a solid r.in.gdal/v.in.ogr).
# For more info have a look at e.g. https://trac.osgeo.org/grass/ticket/3927
ProcessingConfig.addSetting(
Setting(
self.name(),
GrassUtils.GRASS_USE_REXTERNAL,
self.tr(
"For raster layers, use r.external (faster) instead of r.in.gdal"
),
False,
)
)
ProcessingConfig.addSetting(
Setting(
self.name(),
GrassUtils.GRASS_USE_VEXTERNAL,
self.tr(
"For vector layers, use v.external (faster) instead of v.in.ogr"
),
False,
)
)
ProcessingConfig.readSettings()
self.refreshAlgorithms()
return True
def unload(self):
ProcessingConfig.removeSetting(GrassUtils.GRASS_LOG_COMMANDS)
ProcessingConfig.removeSetting(GrassUtils.GRASS_LOG_CONSOLE)
ProcessingConfig.removeSetting(GrassUtils.GRASS_HELP_URL)
ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_REXTERNAL)
ProcessingConfig.removeSetting(GrassUtils.GRASS_USE_VEXTERNAL)
def parse_algorithms(self) -> list[QgsProcessingAlgorithm]:
"""
Parses all algorithm sources and returns a list of all GRASS
algorithms.
"""
algs = []
for folder in GrassUtils.grassDescriptionFolders():
if (folder / "algorithms.json").exists():
# fast approach -- use aggregated JSON summary of algorithms
with open(folder / "algorithms.json", encoding="utf8") as f_in:
algorithm_strings = f_in.read()
algorithms_json = json.loads(algorithm_strings)
for algorithm_json in algorithms_json:
try:
alg = GrassAlgorithm(
json_definition=algorithm_json, description_folder=folder
)
if alg.name().strip() != "":
algs.append(alg)
else:
QgsMessageLog.logMessage(
self.tr(
"Could not open GRASS GIS algorithm: {0}"
).format(algorithm_json.get("name")),
self.tr("Processing"),
Qgis.MessageLevel.Critical,
)
except Exception as e:
QgsMessageLog.logMessage(
self.tr(
"Could not open GRASS GIS algorithm: {0}\n{1}"
).format(algorithm_json.get("name"), e),
self.tr("Processing"),
Qgis.MessageLevel.Critical,
)
else:
# slow approach - pass txt files one by one
for descriptionFile in folder.glob("*.txt"):
try:
alg = GrassAlgorithm(description_file=descriptionFile)
if alg.name().strip() != "":
algs.append(alg)
else:
QgsMessageLog.logMessage(
self.tr(
"Could not open GRASS GIS algorithm: {0}"
).format(descriptionFile),
self.tr("Processing"),
Qgis.MessageLevel.Critical,
)
except Exception as e:
QgsMessageLog.logMessage(
self.tr(
"Could not open GRASS GIS algorithm: {0}\n{1}"
).format(descriptionFile, e),
self.tr("Processing"),
Qgis.MessageLevel.Critical,
)
return algs
def loadAlgorithms(self):
version = GrassUtils.installedVersion(True)
if version is None:
QgsMessageLog.logMessage(
self.tr(
"Problem with GRASS installation: GRASS was not found or is not correctly installed"
),
self.tr("Processing"),
Qgis.MessageLevel.Critical,
)
return
for a in self.parse_algorithms():
self.addAlgorithm(a)
def name(self):
return "GRASS"
def longName(self):
version = GrassUtils.installedVersion()
return f"GRASS GIS ({version})" if version is not None else "GRASS GIS"
def id(self):
return "grass"
def helpId(self):
return "grass7"
def icon(self):
return QgsApplication.getThemeIcon("/providerGrass.svg")
def svgIconPath(self):
return QgsApplication.iconPath("/providerGrass.svg")
def versionInfo(self):
return GrassUtils.installedVersion() or None
def supportsNonFileBasedOutput(self):
"""
GRASS Provider doesn't support non file based outputs
"""
return False
def supportedOutputVectorLayerExtensions(self):
# We use the same extensions as QGIS because:
# - QGIS is using OGR like GRASS
# - There are very few chances that OGR version used in GRASS is
# different from QGIS OGR version.
return super().supportedOutputVectorLayerExtensions()
def supportedOutputRasterLayerExtensions(self):
return GrassUtils.getSupportedOutputRasterExtensions()
def canBeActivated(self):
return not bool(GrassUtils.checkGrassIsInstalled())
def tr(self, string, context=""):
if context == "":
context = "Grass7AlgorithmProvider"
return QCoreApplication.translate(context, string)