QGIS/python/plugins/processing/modeler/ModelerParameterDefinitionDialog.py

422 lines
22 KiB
Python
Raw Normal View History

2012-10-04 19:33:47 +02:00
# -*- coding: utf-8 -*-
"""
***************************************************************************
ModelerParameterDefinitionDialog.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. *
* *
***************************************************************************
"""
2013-08-20 11:04:32 +03:00
2012-10-04 19:33:47 +02:00
__author__ = 'Victor Olaya'
__date__ = 'August 2012'
__copyright__ = '(C) 2012, Victor Olaya'
2012-10-04 19:33:47 +02:00
# This will get replaced with a git SHA1 when you do a git archive
2012-10-04 19:33:47 +02:00
__revision__ = '$Format:%H$'
import math
from qgis.gui import QgsExpressionLineEdit, QgsProjectionSelectionWidget
from qgis.core import (QgsSettings,
QgsProcessing,
QgsCoordinateReferenceSystem,
2017-06-13 13:22:19 +10:00
QgsProcessingParameterDefinition,
QgsProcessingParameterBoolean,
QgsProcessingParameterCrs,
QgsProcessingParameterMapLayer,
QgsProcessingParameterExtent,
QgsProcessingParameterPoint,
QgsProcessingParameterFile,
QgsProcessingParameterMatrix,
QgsProcessingParameterMultipleLayers,
QgsProcessingParameterNumber,
QgsProcessingParameterRange,
QgsProcessingParameterRasterLayer,
QgsProcessingParameterEnum,
QgsProcessingParameterString,
QgsProcessingParameterExpression,
QgsProcessingParameterVectorLayer,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterBand)
from qgis.PyQt.QtCore import (Qt,
QByteArray,
QCoreApplication)
from qgis.PyQt.QtWidgets import (QDialog,
QVBoxLayout,
QLabel,
QLineEdit,
QComboBox,
QCheckBox,
QDialogButtonBox,
QMessageBox)
from processing.core import parameters
2012-09-15 18:25:25 +03:00
class ModelerParameterDefinitionDialog(QDialog):
def __init__(self, alg, paramType=None, param=None):
self.alg = alg
2012-09-15 18:25:25 +03:00
self.paramType = paramType
self.param = param
QDialog.__init__(self)
2012-09-15 18:25:25 +03:00
self.setModal(True)
self.setupUi()
settings = QgsSettings()
self.restoreGeometry(settings.value("/Processing/modelParametersDefinitionDialogGeometry", QByteArray()))
def closeEvent(self, event):
settings = QgsSettings()
settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
super(ModelerParameterDefinitionDialog, self).closeEvent(event)
2012-09-15 18:25:25 +03:00
def setupUi(self):
2017-11-18 18:52:45 +01:00
self.setWindowTitle(self.tr('Parameter Definition'))
self.setMinimumWidth(300)
2012-09-15 18:25:25 +03:00
self.verticalLayout = QVBoxLayout(self)
2012-09-15 18:25:25 +03:00
self.verticalLayout.setMargin(20)
self.label = QLabel(self.tr('Parameter name'))
self.verticalLayout.addWidget(self.label)
self.nameTextBox = QLineEdit()
self.verticalLayout.addWidget(self.nameTextBox)
2012-09-15 18:25:25 +03:00
2017-05-16 16:36:00 +10:00
if isinstance(self.param, QgsProcessingParameterDefinition):
self.nameTextBox.setText(self.param.description())
if self.paramType == parameters.PARAMETER_BOOLEAN or \
2017-06-13 13:22:19 +10:00
isinstance(self.param, QgsProcessingParameterBoolean):
self.state = QCheckBox()
self.state.setText(self.tr('Checked'))
self.state.setChecked(False)
if self.param is not None:
2017-06-13 13:22:19 +10:00
self.state.setChecked(bool(self.param.defaultValue()))
self.verticalLayout.addWidget(self.state)
elif self.paramType == parameters.PARAMETER_TABLE_FIELD or \
isinstance(self.param, QgsProcessingParameterField):
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
idx = 0
2017-06-13 16:05:59 +10:00
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
2017-06-13 16:05:59 +10:00
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
# add the datatype selector
self.verticalLayout.addWidget(QLabel(self.tr('Allowed data type')))
self.datatypeCombo = QComboBox()
self.datatypeCombo.addItem(self.tr('Any'), -1)
self.datatypeCombo.addItem(self.tr('Number'), 0)
self.datatypeCombo.addItem(self.tr('String'), 1)
self.datatypeCombo.addItem(self.tr('Date/time'), 2)
self.verticalLayout.addWidget(self.datatypeCombo)
2017-06-13 13:22:19 +10:00
if self.param is not None and self.param.dataType() is not None:
# QComboBoxes indexes start at 0,
# self.param.datatype start with -1 that is why I need to do +1
2017-06-13 13:22:19 +10:00
datatypeIndex = self.param.dataType() + 1
self.datatypeCombo.setCurrentIndex(datatypeIndex)
self.multipleCheck = QCheckBox()
self.multipleCheck.setText(self.tr('Accept multiple fields'))
self.multipleCheck.setChecked(False)
if self.param is not None:
2017-06-13 13:22:19 +10:00
self.multipleCheck.setChecked(self.param.allowMultiple())
self.verticalLayout.addWidget(self.multipleCheck)
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
2017-09-22 10:56:32 +10:00
self.defaultTextBox.setToolTip(
self.tr('Default field name, or ; separated list of field names for multiple field parameters'))
if self.param is not None:
default = self.param.defaultValue()
if default is not None:
self.defaultTextBox.setText(str(default))
self.verticalLayout.addWidget(self.defaultTextBox)
elif self.paramType == parameters.PARAMETER_BAND or \
isinstance(self.param, QgsProcessingParameterBand):
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
idx = 0
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterRasterLayer)):
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
2017-09-22 10:56:32 +10:00
elif (self.paramType in (
parameters.PARAMETER_VECTOR, parameters.PARAMETER_TABLE) or
isinstance(self.param, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer))):
self.verticalLayout.addWidget(QLabel(self.tr('Geometry type')))
self.shapetypeCombo = QComboBox()
self.shapetypeCombo.addItem(self.tr('Geometry Not Required'), QgsProcessing.TypeVector)
self.shapetypeCombo.addItem(self.tr('Point'), QgsProcessing.TypeVectorPoint)
self.shapetypeCombo.addItem(self.tr('Line'), QgsProcessing.TypeVectorLine)
self.shapetypeCombo.addItem(self.tr('Polygon'), QgsProcessing.TypeVectorPolygon)
self.shapetypeCombo.addItem(self.tr('Any Geometry Type'), QgsProcessing.TypeVectorAnyGeometry)
if self.param is not None:
self.shapetypeCombo.setCurrentIndex(self.shapetypeCombo.findData(self.param.dataTypes()[0]))
self.verticalLayout.addWidget(self.shapetypeCombo)
elif (self.paramType == parameters.PARAMETER_MULTIPLE or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterMultipleLayers)):
self.verticalLayout.addWidget(QLabel(self.tr('Data type')))
self.datatypeCombo = QComboBox()
self.datatypeCombo.addItem(self.tr('Any Map Layer'), QgsProcessing.TypeMapLayer)
self.datatypeCombo.addItem(self.tr('Vector (No Geometry Required)'), QgsProcessing.TypeVector)
self.datatypeCombo.addItem(self.tr('Vector (Point)'), QgsProcessing.TypeVectorPoint)
self.datatypeCombo.addItem(self.tr('Vector (Line)'), QgsProcessing.TypeVectorLine)
self.datatypeCombo.addItem(self.tr('Vector (Polygon)'), QgsProcessing.TypeVectorPolygon)
self.datatypeCombo.addItem(self.tr('Vector (Any Geometry Type)'), QgsProcessing.TypeVectorAnyGeometry)
self.datatypeCombo.addItem(self.tr('Raster'), QgsProcessing.TypeRaster)
self.datatypeCombo.addItem(self.tr('File'), QgsProcessing.TypeFile)
if self.param is not None:
self.datatypeCombo.setCurrentIndex(self.datatypeCombo.findData(self.param.layerType()))
self.verticalLayout.addWidget(self.datatypeCombo)
elif (self.paramType == parameters.PARAMETER_NUMBER or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterNumber)):
self.verticalLayout.addWidget(QLabel(self.tr('Min value')))
self.minTextBox = QLineEdit()
self.verticalLayout.addWidget(self.minTextBox)
self.verticalLayout.addWidget(QLabel(self.tr('Max value')))
self.maxTextBox = QLineEdit()
self.verticalLayout.addWidget(self.maxTextBox)
if self.param is not None:
2017-06-13 13:22:19 +10:00
self.minTextBox.setText(str(self.param.minimum()))
self.maxTextBox.setText(str(self.param.maximum()))
2016-10-31 09:12:39 +10:00
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
self.defaultTextBox.setText(self.tr('0'))
if self.param is not None:
2017-06-13 13:22:19 +10:00
default = self.param.defaultValue()
if self.param.dataType() == QgsProcessingParameterNumber.Integer:
default = int(math.floor(default))
if default:
2016-09-27 19:51:06 +02:00
self.defaultTextBox.setText(str(default))
self.verticalLayout.addWidget(self.defaultTextBox)
elif (self.paramType == parameters.PARAMETER_EXPRESSION or
2017-06-13 13:22:19 +10:00
isinstance(self.param, QgsProcessingParameterExpression)):
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultEdit = QgsExpressionLineEdit()
if self.param is not None:
2017-05-16 16:36:00 +10:00
self.defaultEdit.setExpression(self.param.defaultValue())
self.verticalLayout.addWidget(self.defaultEdit)
self.verticalLayout.addWidget(QLabel(self.tr('Parent layer')))
self.parentCombo = QComboBox()
self.parentCombo.addItem(self.tr("None"), None)
idx = 1
2017-06-13 16:05:59 +10:00
for param in list(self.alg.parameterComponents().values()):
definition = self.alg.parameterDefinition(param.parameterName())
if isinstance(definition, (QgsProcessingParameterFeatureSource, QgsProcessingParameterVectorLayer)):
2017-06-13 16:05:59 +10:00
self.parentCombo.addItem(definition.description(), definition.name())
if self.param is not None:
if self.param.parentLayerParameterName() == definition.name():
self.parentCombo.setCurrentIndex(idx)
idx += 1
self.verticalLayout.addWidget(self.parentCombo)
elif (self.paramType == parameters.PARAMETER_STRING or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterString)):
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
if self.param is not None:
2017-05-16 16:36:00 +10:00
self.defaultTextBox.setText(self.param.defaultValue())
self.verticalLayout.addWidget(self.defaultTextBox)
elif (self.paramType == parameters.PARAMETER_FILE or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterFile)):
self.verticalLayout.addWidget(QLabel(self.tr('Type')))
self.fileFolderCombo = QComboBox()
self.fileFolderCombo.addItem(self.tr('File'))
self.fileFolderCombo.addItem(self.tr('Folder'))
if self.param is not None:
self.fileFolderCombo.setCurrentIndex(
2017-06-13 13:22:19 +10:00
1 if self.param.behavior() == QgsProcessingParameterFile.Folder else 0)
self.verticalLayout.addWidget(self.fileFolderCombo)
elif (self.paramType == parameters.PARAMETER_POINT or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterPoint)):
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.defaultTextBox = QLineEdit()
if self.param is not None:
2017-05-16 16:36:00 +10:00
self.defaultTextBox.setText(self.param.defaultValue())
self.verticalLayout.addWidget(self.defaultTextBox)
elif (self.paramType == parameters.PARAMETER_CRS or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterCrs)):
self.verticalLayout.addWidget(QLabel(self.tr('Default value')))
self.selector = QgsProjectionSelectionWidget()
if self.param is not None:
2017-05-16 16:36:00 +10:00
self.selector.setCrs(QgsCoordinateReferenceSystem(self.param.defaultValue()))
else:
self.selector.setCrs(QgsCoordinateReferenceSystem('EPSG:4326'))
self.verticalLayout.addWidget(self.selector)
2012-09-15 18:25:25 +03:00
self.verticalLayout.addSpacing(20)
self.requiredCheck = QCheckBox()
self.requiredCheck.setText(self.tr('Mandatory'))
self.requiredCheck.setChecked(True)
if self.param is not None:
2017-05-16 16:36:00 +10:00
self.requiredCheck.setChecked(not self.param.flags() & QgsProcessingParameterDefinition.FlagOptional)
self.verticalLayout.addWidget(self.requiredCheck)
self.buttonBox = QDialogButtonBox(self)
self.buttonBox.setOrientation(Qt.Horizontal)
2017-01-25 03:28:53 +01:00
self.buttonBox.setStandardButtons(QDialogButtonBox.Cancel |
QDialogButtonBox.Ok)
self.buttonBox.setObjectName('buttonBox')
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
2013-05-01 23:45:20 +02:00
self.verticalLayout.addStretch()
2012-09-15 18:25:25 +03:00
self.verticalLayout.addWidget(self.buttonBox)
2013-05-01 23:45:20 +02:00
2012-09-15 18:25:25 +03:00
self.setLayout(self.verticalLayout)
def accept(self):
2016-09-21 18:24:26 +02:00
description = str(self.nameTextBox.text())
if description.strip() == '':
QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Invalid parameter name'))
2012-09-15 18:25:25 +03:00
return
if self.param is None:
validChars = \
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
safeName = ''.join(c for c in description if c in validChars)
name = safeName.lower()
i = 2
2017-06-13 16:05:59 +10:00
while self.alg.parameterDefinition(name):
name = safeName.lower() + str(i)
2017-06-13 16:05:59 +10:00
i += 1
2012-09-15 18:25:25 +03:00
else:
2017-05-16 16:36:00 +10:00
name = self.param.name()
if (self.paramType == parameters.PARAMETER_BOOLEAN or
2017-06-13 13:22:19 +10:00
isinstance(self.param, QgsProcessingParameterBoolean)):
self.param = QgsProcessingParameterBoolean(name, description, self.state.isChecked())
elif (self.paramType == parameters.PARAMETER_TABLE_FIELD or
isinstance(self.param, QgsProcessingParameterField)):
2012-09-15 18:25:25 +03:00
if self.parentCombo.currentIndex() < 0:
QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Wrong or missing parameter values'))
2012-09-15 18:25:25 +03:00
return
2017-01-25 03:28:53 +01:00
parent = self.parentCombo.currentData()
datatype = self.datatypeCombo.currentData()
default = self.defaultTextBox.text()
if not default:
default = None
2017-09-22 10:56:32 +10:00
self.param = QgsProcessingParameterField(name, description, defaultValue=default,
parentLayerParameterName=parent, type=datatype,
allowMultiple=self.multipleCheck.isChecked())
elif (self.paramType == parameters.PARAMETER_BAND or
isinstance(self.param, QgsProcessingParameterBand)):
if self.parentCombo.currentIndex() < 0:
QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Wrong or missing parameter values'))
return
parent = self.parentCombo.currentData()
self.param = QgsProcessingParameterBand(name, description, None, parent)
elif (self.paramType == parameters.PARAMETER_MAP_LAYER or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterMapLayer)):
self.param = QgsProcessingParameterMapLayer(
name, description)
elif (self.paramType == parameters.PARAMETER_RASTER or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterRasterLayer)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterRasterLayer(
name, description)
elif (self.paramType == parameters.PARAMETER_TABLE or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterVectorLayer)):
self.param = QgsProcessingParameterVectorLayer(
name, description,
[self.shapetypeCombo.currentData()])
elif (self.paramType == parameters.PARAMETER_VECTOR or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterFeatureSource)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterFeatureSource(
name, description,
[self.shapetypeCombo.currentData()])
elif (self.paramType == parameters.PARAMETER_MULTIPLE or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterMultipleLayers)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterMultipleLayers(
name, description,
self.datatypeCombo.currentData())
elif (self.paramType == parameters.PARAMETER_NUMBER or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterNumber)):
2012-09-15 18:25:25 +03:00
try:
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterNumber(name, description, QgsProcessingParameterNumber.Double,
self.defaultTextBox.text())
vmin = self.minTextBox.text().strip()
2017-06-13 13:22:19 +10:00
if not vmin == '':
self.param.setMinimum(float(vmin))
vmax = self.maxTextBox.text().strip()
2017-06-13 13:22:19 +10:00
if not vmax == '':
self.param.setMaximum(float(vmax))
2012-09-15 18:25:25 +03:00
except:
QMessageBox.warning(self, self.tr('Unable to define parameter'),
self.tr('Wrong or missing parameter values'))
return
elif (self.paramType == parameters.PARAMETER_EXPRESSION or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterExpression)):
2017-01-25 03:28:53 +01:00
parent = self.parentCombo.currentData()
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterExpression(name, description,
str(self.defaultEdit.expression()),
parent)
elif (self.paramType == parameters.PARAMETER_STRING or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterString)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterString(name, description,
str(self.defaultTextBox.text()))
elif (self.paramType == parameters.PARAMETER_EXTENT or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterExtent)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterExtent(name, description)
elif (self.paramType == parameters.PARAMETER_FILE or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterFile)):
isFolder = self.fileFolderCombo.currentIndex() == 1
2017-09-22 10:56:32 +10:00
self.param = QgsProcessingParameterFile(name, description,
QgsProcessingParameterFile.Folder if isFolder else QgsProcessingParameterFile.File)
elif (self.paramType == parameters.PARAMETER_POINT or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterPoint)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterPoint(name, description,
str(self.defaultTextBox.text()))
elif (self.paramType == parameters.PARAMETER_CRS or
2017-09-22 10:56:32 +10:00
isinstance(self.param, QgsProcessingParameterCrs)):
2017-06-13 13:22:19 +10:00
self.param = QgsProcessingParameterCrs(name, description, self.selector.crs().authid())
else:
from processing.core.Processing import Processing
param = Processing.registeredParameters()[self.paramType]
self.param = param['parameter'](name, description, None)
self.param.setMetadata(param['metadata'])
2017-05-16 16:36:00 +10:00
if not self.requiredCheck.isChecked():
self.param.setFlags(self.param.flags() | QgsProcessingParameterDefinition.FlagOptional)
2012-09-15 18:25:25 +03:00
settings = QgsSettings()
settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
QDialog.accept(self)
def reject(self):
2012-09-15 18:25:25 +03:00
self.param = None
settings = QgsSettings()
settings.setValue("/Processing/modelParametersDefinitionDialogGeometry", self.saveGeometry())
QDialog.reject(self)