mirror of
				https://github.com/qgis/QGIS.git
				synced 2025-10-31 00:06:02 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			490 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			490 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| """
 | |
| ***************************************************************************
 | |
|     ProcessingConfig.py
 | |
|     ---------------------
 | |
|     Date                 : August 2012
 | |
|     Copyright            : (C) 2012 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__ = "August 2012"
 | |
| __copyright__ = "(C) 2012, Victor Olaya"
 | |
| 
 | |
| import os
 | |
| import tempfile
 | |
| 
 | |
| from qgis.PyQt.QtCore import QCoreApplication, QObject, pyqtSignal
 | |
| from qgis.core import (
 | |
|     NULL,
 | |
|     QgsApplication,
 | |
|     QgsSettings,
 | |
|     QgsVectorFileWriter,
 | |
|     QgsRasterFileWriter,
 | |
|     QgsProcessingUtils,
 | |
| )
 | |
| from processing.tools.system import defaultOutputFolder
 | |
| import processing.tools.dataobjects
 | |
| from multiprocessing import cpu_count
 | |
| 
 | |
| 
 | |
| class SettingsWatcher(QObject):
 | |
|     settingsChanged = pyqtSignal()
 | |
| 
 | |
| 
 | |
| settingsWatcher = SettingsWatcher()
 | |
| 
 | |
| 
 | |
| class ProcessingConfig:
 | |
|     OUTPUT_FOLDER = "OUTPUTS_FOLDER"
 | |
|     RASTER_STYLE = "RASTER_STYLE"
 | |
|     VECTOR_POINT_STYLE = "VECTOR_POINT_STYLE"
 | |
|     VECTOR_LINE_STYLE = "VECTOR_LINE_STYLE"
 | |
|     VECTOR_POLYGON_STYLE = "VECTOR_POLYGON_STYLE"
 | |
|     FILTER_INVALID_GEOMETRIES = "FILTER_INVALID_GEOMETRIES"
 | |
|     PREFER_FILENAME_AS_LAYER_NAME = "prefer-filename-as-layer-name"
 | |
|     KEEP_DIALOG_OPEN = "KEEP_DIALOG_OPEN"
 | |
|     PRE_EXECUTION_SCRIPT = "PRE_EXECUTION_SCRIPT"
 | |
|     POST_EXECUTION_SCRIPT = "POST_EXECUTION_SCRIPT"
 | |
|     SHOW_CRS_DEF = "SHOW_CRS_DEF"
 | |
|     WARN_UNMATCHING_CRS = "WARN_UNMATCHING_CRS"
 | |
|     SHOW_PROVIDERS_TOOLTIP = "SHOW_PROVIDERS_TOOLTIP"
 | |
|     SHOW_ALGORITHMS_KNOWN_ISSUES = "SHOW_ALGORITHMS_KNOWN_ISSUES"
 | |
|     MAX_THREADS = "MAX_THREADS"
 | |
|     DEFAULT_OUTPUT_RASTER_LAYER_EXT = "default-output-raster-ext"
 | |
|     DEFAULT_OUTPUT_VECTOR_LAYER_EXT = "default-output-vector-ext"
 | |
|     TEMP_PATH = "temp-path"
 | |
|     RESULTS_GROUP_NAME = "RESULTS_GROUP_NAME"
 | |
|     VECTOR_FEATURE_COUNT = "VECTOR_FEATURE_COUNT"
 | |
| 
 | |
|     settings = {}
 | |
|     settingIcons = {}
 | |
| 
 | |
|     @staticmethod
 | |
|     def initialize():
 | |
|         icon = QgsApplication.getThemeIcon("/processingAlgorithm.svg")
 | |
|         ProcessingConfig.settingIcons["General"] = icon
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.KEEP_DIALOG_OPEN,
 | |
|                 ProcessingConfig.tr("Keep dialog open after running an algorithm"),
 | |
|                 True,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.PREFER_FILENAME_AS_LAYER_NAME,
 | |
|                 ProcessingConfig.tr("Prefer output filename for layer names"),
 | |
|                 True,
 | |
|                 hasSettingEntry=True,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.SHOW_PROVIDERS_TOOLTIP,
 | |
|                 ProcessingConfig.tr("Show tooltip when there are disabled providers"),
 | |
|                 True,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.OUTPUT_FOLDER,
 | |
|                 ProcessingConfig.tr("Output folder"),
 | |
|                 defaultOutputFolder(),
 | |
|                 valuetype=Setting.FOLDER,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.SHOW_CRS_DEF,
 | |
|                 ProcessingConfig.tr("Show layer CRS definition in selection boxes"),
 | |
|                 True,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.WARN_UNMATCHING_CRS,
 | |
|                 ProcessingConfig.tr(
 | |
|                     "Warn before executing if parameter CRS's do not match"
 | |
|                 ),
 | |
|                 True,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.SHOW_ALGORITHMS_KNOWN_ISSUES,
 | |
|                 ProcessingConfig.tr("Show algorithms with known issues"),
 | |
|                 False,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.RASTER_STYLE,
 | |
|                 ProcessingConfig.tr("Style for raster layers"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.VECTOR_POINT_STYLE,
 | |
|                 ProcessingConfig.tr("Style for point layers"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.VECTOR_LINE_STYLE,
 | |
|                 ProcessingConfig.tr("Style for line layers"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.VECTOR_POLYGON_STYLE,
 | |
|                 ProcessingConfig.tr("Style for polygon layers"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.PRE_EXECUTION_SCRIPT,
 | |
|                 ProcessingConfig.tr("Pre-execution script"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.POST_EXECUTION_SCRIPT,
 | |
|                 ProcessingConfig.tr("Post-execution script"),
 | |
|                 "",
 | |
|                 valuetype=Setting.FILE,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         invalidFeaturesOptions = [
 | |
|             ProcessingConfig.tr("Do not filter (better performance)"),
 | |
|             ProcessingConfig.tr("Skip (ignore) features with invalid geometries"),
 | |
|             ProcessingConfig.tr("Stop algorithm execution when a geometry is invalid"),
 | |
|         ]
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.FILTER_INVALID_GEOMETRIES,
 | |
|                 ProcessingConfig.tr("Invalid features filtering"),
 | |
|                 invalidFeaturesOptions[2],
 | |
|                 valuetype=Setting.SELECTION,
 | |
|                 options=invalidFeaturesOptions,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         threads = (
 | |
|             QgsApplication.maxThreads()
 | |
|         )  # if user specified limit for rendering, lets keep that as default here, otherwise max
 | |
|         threads = (
 | |
|             cpu_count() if threads == -1 else threads
 | |
|         )  # if unset, maxThreads() returns -1
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.MAX_THREADS,
 | |
|                 ProcessingConfig.tr("Max Threads"),
 | |
|                 threads,
 | |
|                 valuetype=Setting.INT,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         extensions = QgsVectorFileWriter.supportedFormatExtensions()
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.DEFAULT_OUTPUT_VECTOR_LAYER_EXT,
 | |
|                 ProcessingConfig.tr("Default output vector layer extension"),
 | |
|                 QgsVectorFileWriter.supportedFormatExtensions()[0],
 | |
|                 valuetype=Setting.SELECTION_STORE_STRING,
 | |
|                 options=extensions,
 | |
|                 hasSettingEntry=True,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         extensions = QgsRasterFileWriter.supportedFormatExtensions()
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.DEFAULT_OUTPUT_RASTER_LAYER_EXT,
 | |
|                 ProcessingConfig.tr("Default output raster layer extension"),
 | |
|                 "tif",
 | |
|                 valuetype=Setting.SELECTION_STORE_STRING,
 | |
|                 options=extensions,
 | |
|                 hasSettingEntry=True,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.TEMP_PATH,
 | |
|                 ProcessingConfig.tr("Override temporary output folder path"),
 | |
|                 None,
 | |
|                 valuetype=Setting.FOLDER,
 | |
|                 placeholder=ProcessingConfig.tr("Leave blank for default"),
 | |
|                 hasSettingEntry=True,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.RESULTS_GROUP_NAME,
 | |
|                 ProcessingConfig.tr("Results group name"),
 | |
|                 "",
 | |
|                 valuetype=Setting.STRING,
 | |
|                 placeholder=ProcessingConfig.tr(
 | |
|                     "Leave blank to avoid loading results in a predetermined group"
 | |
|                 ),
 | |
|             )
 | |
|         )
 | |
| 
 | |
|         ProcessingConfig.addSetting(
 | |
|             Setting(
 | |
|                 ProcessingConfig.tr("General"),
 | |
|                 ProcessingConfig.VECTOR_FEATURE_COUNT,
 | |
|                 ProcessingConfig.tr("Show feature count for output vector layers"),
 | |
|                 False,
 | |
|             )
 | |
|         )
 | |
| 
 | |
|     @staticmethod
 | |
|     def setGroupIcon(group, icon):
 | |
|         ProcessingConfig.settingIcons[group] = icon
 | |
| 
 | |
|     @staticmethod
 | |
|     def getGroupIcon(group):
 | |
|         if group == ProcessingConfig.tr("General"):
 | |
|             return QgsApplication.getThemeIcon("/processingAlgorithm.svg")
 | |
|         if group in ProcessingConfig.settingIcons:
 | |
|             return ProcessingConfig.settingIcons[group]
 | |
|         else:
 | |
|             return QgsApplication.getThemeIcon("/processingAlgorithm.svg")
 | |
| 
 | |
|     @staticmethod
 | |
|     def addSetting(setting):
 | |
|         ProcessingConfig.settings[setting.name] = setting
 | |
| 
 | |
|     @staticmethod
 | |
|     def removeSetting(name):
 | |
|         del ProcessingConfig.settings[name]
 | |
| 
 | |
|     @staticmethod
 | |
|     def getSettings():
 | |
|         """Return settings as a dict with group names as keys and lists of settings as values"""
 | |
|         settings = {}
 | |
|         for setting in list(ProcessingConfig.settings.values()):
 | |
|             if setting.group not in settings:
 | |
|                 group = []
 | |
|                 settings[setting.group] = group
 | |
|             else:
 | |
|                 group = settings[setting.group]
 | |
|             group.append(setting)
 | |
|         return settings
 | |
| 
 | |
|     @staticmethod
 | |
|     def readSettings():
 | |
|         for setting in list(ProcessingConfig.settings.values()):
 | |
|             setting.read()
 | |
| 
 | |
|     @staticmethod
 | |
|     def getSetting(name, readable=False):
 | |
|         if name not in list(ProcessingConfig.settings.keys()):
 | |
|             return None
 | |
|         v = ProcessingConfig.settings[name].value
 | |
|         try:
 | |
|             if v == NULL:
 | |
|                 v = None
 | |
|         except:
 | |
|             pass
 | |
|         if ProcessingConfig.settings[name].valuetype != Setting.SELECTION:
 | |
|             return v
 | |
|         if readable:
 | |
|             return v
 | |
|         return ProcessingConfig.settings[name].options.index(v)
 | |
| 
 | |
|     @staticmethod
 | |
|     def setSettingValue(name, value):
 | |
|         if name in list(ProcessingConfig.settings.keys()):
 | |
|             if ProcessingConfig.settings[name].valuetype == Setting.SELECTION:
 | |
|                 ProcessingConfig.settings[name].setValue(
 | |
|                     ProcessingConfig.settings[name].options[value]
 | |
|                 )
 | |
|             else:
 | |
|                 ProcessingConfig.settings[name].setValue(value)
 | |
|             ProcessingConfig.settings[name].save()
 | |
| 
 | |
|     @staticmethod
 | |
|     def tr(string, context=""):
 | |
|         if context == "":
 | |
|             context = "ProcessingConfig"
 | |
|         return QCoreApplication.translate(context, string)
 | |
| 
 | |
| 
 | |
| class Setting:
 | |
|     """A simple config parameter that will appear on the config dialog."""
 | |
| 
 | |
|     STRING = 0
 | |
|     FILE = 1
 | |
|     FOLDER = 2
 | |
|     SELECTION = 3
 | |
|     FLOAT = 4
 | |
|     INT = 5
 | |
|     MULTIPLE_FOLDERS = 6
 | |
|     SELECTION_STORE_STRING = 7
 | |
| 
 | |
|     def __init__(
 | |
|         self,
 | |
|         group,
 | |
|         name,
 | |
|         description,
 | |
|         default,
 | |
|         hidden=False,
 | |
|         valuetype=None,
 | |
|         validator=None,
 | |
|         options=None,
 | |
|         placeholder="",
 | |
|         hasSettingEntry=False,
 | |
|     ):
 | |
|         """
 | |
|         hasSettingEntry is true if the given setting is part of QgsSettingsRegistry entries
 | |
|         """
 | |
|         self.group = group
 | |
|         self.name = name
 | |
|         self.qname = (
 | |
|             "qgis/configuration/" if hasSettingEntry else "Processing/Configuration/"
 | |
|         ) + self.name
 | |
|         self.description = description
 | |
|         self.default = default
 | |
|         self.hidden = hidden
 | |
|         self.valuetype = valuetype
 | |
|         self.options = options
 | |
|         self.placeholder = placeholder
 | |
| 
 | |
|         if self.valuetype is None:
 | |
|             if isinstance(default, int):
 | |
|                 self.valuetype = self.INT
 | |
|             elif isinstance(default, float):
 | |
|                 self.valuetype = self.FLOAT
 | |
| 
 | |
|         if validator is None:
 | |
|             if self.valuetype == self.FLOAT:
 | |
| 
 | |
|                 def checkFloat(v):
 | |
|                     try:
 | |
|                         float(v)
 | |
|                     except ValueError:
 | |
|                         raise ValueError(
 | |
|                             self.tr("Wrong parameter value:\n{0}").format(v)
 | |
|                         )
 | |
| 
 | |
|                 validator = checkFloat
 | |
|             elif self.valuetype == self.INT:
 | |
| 
 | |
|                 def checkInt(v):
 | |
|                     try:
 | |
|                         int(v)
 | |
|                     except ValueError:
 | |
|                         raise ValueError(
 | |
|                             self.tr("Wrong parameter value:\n{0}").format(v)
 | |
|                         )
 | |
| 
 | |
|                 validator = checkInt
 | |
|             elif self.valuetype in [self.FILE, self.FOLDER]:
 | |
| 
 | |
|                 def checkFileOrFolder(v):
 | |
|                     if v and not os.path.exists(v):
 | |
|                         raise ValueError(
 | |
|                             self.tr("Specified path does not exist:\n{0}").format(v)
 | |
|                         )
 | |
| 
 | |
|                 validator = checkFileOrFolder
 | |
|             elif self.valuetype == self.MULTIPLE_FOLDERS:
 | |
| 
 | |
|                 def checkMultipleFolders(v):
 | |
|                     folders = v.split(";")
 | |
|                     for f in folders:
 | |
|                         if f and not os.path.exists(f):
 | |
|                             raise ValueError(
 | |
|                                 self.tr("Specified path does not exist:\n{0}").format(f)
 | |
|                             )
 | |
| 
 | |
|                 validator = checkMultipleFolders
 | |
|             else:
 | |
| 
 | |
|                 def validator(x):
 | |
|                     return True
 | |
| 
 | |
|         self.validator = validator
 | |
|         self.value = default
 | |
| 
 | |
|     def setValue(self, value):
 | |
|         self.validator(value)
 | |
|         self.value = value
 | |
| 
 | |
|     def read(self, qsettings=None):
 | |
|         if not qsettings:
 | |
|             qsettings = QgsSettings()
 | |
|         value = qsettings.value(self.qname, None)
 | |
|         if value is not None:
 | |
|             if isinstance(self.value, bool):
 | |
|                 value = str(value).lower() == str(True).lower()
 | |
| 
 | |
|             if self.valuetype == self.SELECTION:
 | |
|                 try:
 | |
|                     self.value = self.options[int(value)]
 | |
|                 except:
 | |
|                     self.value = self.options[0]
 | |
|             else:
 | |
|                 self.value = value
 | |
| 
 | |
|     def save(self, qsettings=None):
 | |
|         if not qsettings:
 | |
|             qsettings = QgsSettings()
 | |
|         if self.value == self.default:
 | |
|             qsettings.remove(self.qname)
 | |
|             return
 | |
|         if self.valuetype == self.SELECTION:
 | |
|             qsettings.setValue(self.qname, self.options.index(self.value))
 | |
|         else:
 | |
|             qsettings.setValue(self.qname, self.value)
 | |
| 
 | |
|     def __str__(self):
 | |
|         return self.name + "=" + str(self.value)
 | |
| 
 | |
|     def tr(self, string, context=""):
 | |
|         if context == "":
 | |
|             context = "ProcessingConfig"
 | |
|         return QCoreApplication.translate(context, string)
 |