mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
490 lines
21 KiB
Python
490 lines
21 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
***************************************************************************
|
|
ParametersPanel.py
|
|
---------------------
|
|
Date : August 2012
|
|
Copyright : (C) 2012 by Victor Olaya
|
|
(C) 2013 by CS Systemes d'information (CS SI)
|
|
Email : volayaf at gmail dot com
|
|
otb at c-s dot fr (CS SI)
|
|
Contributors : Victor Olaya
|
|
|
|
***************************************************************************
|
|
* *
|
|
* 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'
|
|
|
|
# This will get replaced with a git SHA1 when you do a git archive
|
|
|
|
__revision__ = '$Format:%H$'
|
|
|
|
import os
|
|
import locale
|
|
|
|
from qgis.core import QgsMapLayerRegistry, QgsMapLayer
|
|
|
|
from qgis.PyQt import uic
|
|
from qgis.PyQt.QtCore import QCoreApplication, QVariant
|
|
from qgis.PyQt.QtWidgets import QWidget, QLayout, QVBoxLayout, QHBoxLayout, QToolButton, QLabel, QCheckBox, QComboBox, QLineEdit, QPlainTextEdit
|
|
from qgis.PyQt.QtGui import QIcon
|
|
|
|
from processing.core.ProcessingConfig import ProcessingConfig
|
|
|
|
from processing.gui.OutputSelectionPanel import OutputSelectionPanel
|
|
from processing.gui.InputLayerSelectorPanel import InputLayerSelectorPanel
|
|
from processing.gui.FixedTablePanel import FixedTablePanel
|
|
from processing.gui.RangePanel import RangePanel
|
|
from processing.gui.MultipleInputPanel import MultipleInputPanel
|
|
from processing.gui.NumberInputPanel import NumberInputPanel
|
|
from processing.gui.ExtentSelectionPanel import ExtentSelectionPanel
|
|
from processing.gui.FileSelectionPanel import FileSelectionPanel
|
|
from processing.gui.CrsSelectionPanel import CrsSelectionPanel
|
|
from processing.gui.PointSelectionPanel import PointSelectionPanel
|
|
from processing.gui.GeometryPredicateSelectionPanel import \
|
|
GeometryPredicateSelectionPanel
|
|
from processing.gui.ListMultiselectWidget import ListMultiSelectWidget
|
|
|
|
from processing.core.parameters import ParameterRaster
|
|
from processing.core.parameters import ParameterVector
|
|
from processing.core.parameters import ParameterTable
|
|
from processing.core.parameters import ParameterBoolean
|
|
from processing.core.parameters import ParameterTableField
|
|
from processing.core.parameters import ParameterTableMultipleField
|
|
from processing.core.parameters import ParameterSelection
|
|
from processing.core.parameters import ParameterFixedTable
|
|
from processing.core.parameters import ParameterRange
|
|
from processing.core.parameters import ParameterMultipleInput
|
|
from processing.core.parameters import ParameterNumber
|
|
from processing.core.parameters import ParameterExtent
|
|
from processing.core.parameters import ParameterFile
|
|
from processing.core.parameters import ParameterCrs
|
|
from processing.core.parameters import ParameterString
|
|
from processing.core.parameters import ParameterPoint
|
|
from processing.core.parameters import ParameterGeometryPredicate
|
|
|
|
from processing.core.outputs import OutputRaster
|
|
from processing.core.outputs import OutputTable
|
|
from processing.core.outputs import OutputVector
|
|
|
|
from processing.tools import dataobjects
|
|
|
|
pluginPath = os.path.split(os.path.dirname(__file__))[0]
|
|
WIDGET, BASE = uic.loadUiType(
|
|
os.path.join(pluginPath, 'ui', 'widgetParametersPanel.ui'))
|
|
|
|
|
|
class ParametersPanel(BASE, WIDGET):
|
|
|
|
NOT_SELECTED = QCoreApplication.translate('ParametersPanel', '[Not selected]')
|
|
|
|
def __init__(self, parent, alg):
|
|
super(ParametersPanel, self).__init__(None)
|
|
self.setupUi(self)
|
|
|
|
self.grpAdvanced.hide()
|
|
|
|
self.layoutMain = self.scrollAreaWidgetContents.layout()
|
|
self.layoutAdvanced = self.grpAdvanced.layout()
|
|
|
|
self.parent = parent
|
|
self.alg = alg
|
|
self.valueItems = {}
|
|
self.labels = {}
|
|
self.widgets = {}
|
|
self.checkBoxes = {}
|
|
self.dependentItems = {}
|
|
self.iterateButtons = {}
|
|
|
|
self.initWidgets()
|
|
|
|
def layerAdded(self, layer):
|
|
if layer.type() == QgsMapLayer.VectorLayer:
|
|
for param in self.alg.parameters:
|
|
if param.hidden:
|
|
continue
|
|
if isinstance(param, ParameterVector):
|
|
if dataobjects.canUseVectorLayer(layer, param.datatype):
|
|
widget = self.valueItems[param.name]
|
|
if isinstance(widget, InputLayerSelectorPanel):
|
|
widget = widget.cmbText
|
|
widget.addItem(self.getExtendedLayerName(layer), layer)
|
|
elif layer.type() == QgsMapLayer.RasterLayer and dataobjects.canUseRasterLayer(layer):
|
|
for param in self.alg.parameters:
|
|
if param.hidden:
|
|
continue
|
|
if isinstance(param, ParameterRaster):
|
|
widget = self.valueItems[param.name].cmbText
|
|
widget.addItem(self.getExtendedLayerName(layer), layer)
|
|
|
|
self.updateMultipleInputs()
|
|
|
|
def layersWillBeRemoved(self, layers):
|
|
for layer in layers:
|
|
self.layerRemoved(layer)
|
|
|
|
def layerRemoved(self, layer):
|
|
layer = QgsMapLayerRegistry.instance().mapLayer(layer)
|
|
widget = None
|
|
if layer.type() == QgsMapLayer.VectorLayer:
|
|
for param in self.alg.parameters:
|
|
if param.hidden:
|
|
continue
|
|
if isinstance(param, ParameterVector):
|
|
widget = self.valueItems[param.name]
|
|
if isinstance(widget, InputLayerSelectorPanel):
|
|
widget = widget.cmbText
|
|
|
|
elif layer.type() == QgsMapLayer.RasterLayer:
|
|
for param in self.alg.parameters:
|
|
if param.hidden:
|
|
continue
|
|
if isinstance(param, ParameterRaster):
|
|
widget = self.valueItems[param.name].cmbText
|
|
|
|
if widget is not None:
|
|
idx = widget.findData(layer)
|
|
if idx != -1:
|
|
widget.removeItem(idx)
|
|
|
|
self.updateMultipleInputs()
|
|
|
|
def updateMultipleInputs(self):
|
|
for param in self.alg.parameters:
|
|
if isinstance(param, ParameterMultipleInput) and param.datatype != dataobjects.TYPE_FILE:
|
|
if param.datatype == dataobjects.TYPE_RASTER:
|
|
options = dataobjects.getRasterLayers(sorting=False)
|
|
elif param.datatype == dataobjects.TYPE_VECTOR_ANY:
|
|
options = dataobjects.getVectorLayers(sorting=False)
|
|
else:
|
|
options = dataobjects.getVectorLayers([param.datatype], sorting=False)
|
|
opts = [self.getExtendedLayerName(opt) for opt in options]
|
|
widget = self.valueItems[param.name]
|
|
widget.updateForOptions(opts)
|
|
|
|
def initWidgets(self):
|
|
# If there are advanced parameters — show corresponding groupbox
|
|
for param in self.alg.parameters:
|
|
if param.isAdvanced:
|
|
self.grpAdvanced.show()
|
|
break
|
|
# Create widgets and put them in layouts
|
|
for param in self.alg.parameters:
|
|
if param.hidden:
|
|
continue
|
|
|
|
desc = param.description
|
|
if isinstance(param, ParameterExtent):
|
|
desc += self.tr(' (xmin, xmax, ymin, ymax)')
|
|
if isinstance(param, ParameterPoint):
|
|
desc += self.tr(' (x, y)')
|
|
try:
|
|
if param.optional:
|
|
desc += self.tr(' [optional]')
|
|
except:
|
|
pass
|
|
|
|
widget = self.getWidgetFromParameter(param)
|
|
self.valueItems[param.name] = widget
|
|
|
|
if isinstance(param, ParameterVector) and \
|
|
not self.alg.allowOnlyOpenedLayers:
|
|
layout = QHBoxLayout()
|
|
layout.setSpacing(2)
|
|
layout.setMargin(0)
|
|
layout.addWidget(widget)
|
|
button = QToolButton()
|
|
icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png'))
|
|
button.setIcon(icon)
|
|
button.setToolTip(self.tr('Iterate over this layer'))
|
|
button.setCheckable(True)
|
|
layout.addWidget(button)
|
|
self.iterateButtons[param.name] = button
|
|
button.toggled.connect(self.buttonToggled)
|
|
widget = QWidget()
|
|
widget.setLayout(layout)
|
|
|
|
tooltips = self.alg.getParameterDescriptions()
|
|
widget.setToolTip(tooltips.get(param.name, param.description))
|
|
|
|
if isinstance(param, ParameterBoolean):
|
|
widget.setText(desc)
|
|
if param.isAdvanced:
|
|
self.layoutAdvanced.addWidget(widget)
|
|
else:
|
|
self.layoutMain.insertWidget(
|
|
self.layoutMain.count() - 2, widget)
|
|
else:
|
|
label = QLabel(desc)
|
|
#label.setToolTip(tooltip)
|
|
self.labels[param.name] = label
|
|
if param.isAdvanced:
|
|
self.layoutAdvanced.addWidget(label)
|
|
self.layoutAdvanced.addWidget(widget)
|
|
else:
|
|
self.layoutMain.insertWidget(
|
|
self.layoutMain.count() - 2, label)
|
|
self.layoutMain.insertWidget(
|
|
self.layoutMain.count() - 2, widget)
|
|
|
|
self.widgets[param.name] = widget
|
|
|
|
for output in self.alg.outputs:
|
|
if output.hidden:
|
|
continue
|
|
|
|
label = QLabel(output.description)
|
|
widget = OutputSelectionPanel(output, self.alg)
|
|
self.layoutMain.insertWidget(self.layoutMain.count() - 1, label)
|
|
self.layoutMain.insertWidget(self.layoutMain.count() - 1, widget)
|
|
if isinstance(output, (OutputRaster, OutputVector, OutputTable)):
|
|
check = QCheckBox()
|
|
check.setText(self.tr('Open output file after running algorithm'))
|
|
check.setChecked(True)
|
|
self.layoutMain.insertWidget(self.layoutMain.count() - 1, check)
|
|
self.checkBoxes[output.name] = check
|
|
self.valueItems[output.name] = widget
|
|
|
|
if isinstance(output, OutputVector):
|
|
if output.base_input in self.dependentItems:
|
|
items = self.dependentItems[output.base_input]
|
|
else:
|
|
items = []
|
|
self.dependentItems[output.base_input] = items
|
|
items.append(output)
|
|
|
|
base_input = self.alg.getParameterFromName(output.base_input)
|
|
if isinstance(base_input, ParameterVector):
|
|
layers = dataobjects.getVectorLayers(base_input.datatype)
|
|
else:
|
|
layers = dataobjects.getTables()
|
|
if len(layers) > 0:
|
|
output.base_layer = layers[0]
|
|
|
|
def buttonToggled(self, value):
|
|
if value:
|
|
sender = self.sender()
|
|
for button in self.iterateButtons.values():
|
|
if button is not sender:
|
|
button.setChecked(False)
|
|
|
|
def getExtendedLayerName(self, layer):
|
|
authid = layer.crs().authid()
|
|
if ProcessingConfig.getSetting(ProcessingConfig.SHOW_CRS_DEF) \
|
|
and authid is not None:
|
|
return u'{} [{}]'.format(layer.name(), authid)
|
|
else:
|
|
return layer.name()
|
|
|
|
def getWidgetFromParameter(self, param):
|
|
# TODO Create Parameter widget class that holds the logic
|
|
# for creating a widget that belongs to the parameter.
|
|
if isinstance(param, ParameterRaster):
|
|
layers = dataobjects.getRasterLayers()
|
|
items = []
|
|
if param.optional:
|
|
items.append((self.NOT_SELECTED, None))
|
|
for layer in layers:
|
|
items.append((self.getExtendedLayerName(layer), layer))
|
|
item = InputLayerSelectorPanel(items, param)
|
|
elif isinstance(param, ParameterVector):
|
|
if self.somethingDependsOnThisParameter(param) or self.alg.allowOnlyOpenedLayers:
|
|
item = QComboBox()
|
|
layers = dataobjects.getVectorLayers(param.datatype)
|
|
layers.sort(key=lambda lay: lay.name())
|
|
if param.optional:
|
|
item.addItem(self.NOT_SELECTED, None)
|
|
for layer in layers:
|
|
item.addItem(self.getExtendedLayerName(layer), layer)
|
|
item.currentIndexChanged.connect(self.updateDependentFields)
|
|
item.name = param.name
|
|
else:
|
|
layers = dataobjects.getVectorLayers(param.datatype)
|
|
items = []
|
|
if param.optional:
|
|
items.append((self.NOT_SELECTED, None))
|
|
for layer in layers:
|
|
items.append((self.getExtendedLayerName(layer), layer))
|
|
# if already set, put first in list
|
|
for i, (name, layer) in enumerate(items):
|
|
if layer and layer.source() == param.value:
|
|
items.insert(0, items.pop(i))
|
|
item = InputLayerSelectorPanel(items, param)
|
|
elif isinstance(param, ParameterTable):
|
|
if self.somethingDependsOnThisParameter(param):
|
|
item = QComboBox()
|
|
layers = dataobjects.getTables()
|
|
if param.optional:
|
|
item.addItem(self.NOT_SELECTED, None)
|
|
for layer in layers:
|
|
item.addItem(layer.name(), layer)
|
|
item.currentIndexChanged.connect(self.updateDependentFields)
|
|
item.name = param.name
|
|
else:
|
|
layers = dataobjects.getTables()
|
|
items = []
|
|
if param.optional:
|
|
items.append((self.NOT_SELECTED, None))
|
|
for layer in layers:
|
|
items.append((layer.name(), layer))
|
|
# if already set, put first in list
|
|
for i, (name, layer) in enumerate(items):
|
|
if layer and layer.source() == param.value:
|
|
items.insert(0, items.pop(i))
|
|
item = InputLayerSelectorPanel(items, param)
|
|
elif isinstance(param, ParameterBoolean):
|
|
item = QCheckBox()
|
|
if param.default:
|
|
item.setChecked(True)
|
|
else:
|
|
item.setChecked(False)
|
|
elif isinstance(param, ParameterTableField) or isinstance(param, ParameterTableMultipleField):
|
|
if isinstance(param, ParameterTableMultipleField):
|
|
item = ListMultiSelectWidget()
|
|
else:
|
|
item = QComboBox()
|
|
if param.parent in self.dependentItems:
|
|
items = self.dependentItems[param.parent]
|
|
else:
|
|
items = []
|
|
self.dependentItems[param.parent] = items
|
|
items.append(param)
|
|
parent = self.alg.getParameterFromName(param.parent)
|
|
if isinstance(parent, ParameterVector):
|
|
layers = dataobjects.getVectorLayers(parent.datatype)
|
|
else:
|
|
layers = dataobjects.getTables()
|
|
if len(layers) > 0:
|
|
if param.optional and isinstance(param, ParameterTableField):
|
|
item.addItem(self.tr('[not set]'))
|
|
item.addItems(self.getFields(layers[0], param.datatype))
|
|
elif isinstance(param, ParameterSelection):
|
|
item = QComboBox()
|
|
item.addItems(param.options)
|
|
if param.default:
|
|
item.setCurrentIndex(param.default)
|
|
elif isinstance(param, ParameterFixedTable):
|
|
item = FixedTablePanel(param)
|
|
elif isinstance(param, ParameterRange):
|
|
item = RangePanel(param)
|
|
elif isinstance(param, ParameterFile):
|
|
item = FileSelectionPanel(param.isFolder, param.ext)
|
|
elif isinstance(param, ParameterMultipleInput):
|
|
if param.datatype == dataobjects.TYPE_FILE:
|
|
item = MultipleInputPanel(datatype=dataobjects.TYPE_FILE)
|
|
else:
|
|
if param.datatype == dataobjects.TYPE_RASTER:
|
|
options = dataobjects.getRasterLayers(sorting=False)
|
|
elif param.datatype == dataobjects.TYPE_VECTOR_ANY:
|
|
options = dataobjects.getVectorLayers(sorting=False)
|
|
else:
|
|
options = dataobjects.getVectorLayers([param.datatype], sorting=False)
|
|
opts = [self.getExtendedLayerName(opt) for opt in options]
|
|
item = MultipleInputPanel(opts)
|
|
elif isinstance(param, ParameterNumber):
|
|
item = NumberInputPanel(param.default, param.min, param.max,
|
|
param.isInteger)
|
|
elif isinstance(param, ParameterExtent):
|
|
item = ExtentSelectionPanel(self.parent, self.alg, param.default)
|
|
elif isinstance(param, ParameterPoint):
|
|
item = PointSelectionPanel(self.parent, param.default)
|
|
elif isinstance(param, ParameterCrs):
|
|
item = CrsSelectionPanel(param.default)
|
|
elif isinstance(param, ParameterString):
|
|
if param.multiline:
|
|
verticalLayout = QVBoxLayout()
|
|
verticalLayout.setSizeConstraint(
|
|
QLayout.SetDefaultConstraint)
|
|
textEdit = QPlainTextEdit()
|
|
if param.default:
|
|
textEdit.setPlainText(param.default)
|
|
verticalLayout.addWidget(textEdit)
|
|
item = textEdit
|
|
else:
|
|
item = QLineEdit()
|
|
if param.default:
|
|
item.setText(unicode(param.default))
|
|
elif isinstance(param, ParameterGeometryPredicate):
|
|
item = GeometryPredicateSelectionPanel(param.enabledPredicates)
|
|
if param.left:
|
|
widget = self.valueItems[param.left]
|
|
if isinstance(widget, InputLayerSelectorPanel):
|
|
widget = widget.cmbText
|
|
widget.currentIndexChanged.connect(item.onLeftLayerChange)
|
|
item.leftLayer = widget.itemData(widget.currentIndex())
|
|
if param.right:
|
|
widget = self.valueItems[param.right]
|
|
if isinstance(widget, InputLayerSelectorPanel):
|
|
widget = widget.cmbText
|
|
widget.currentIndexChanged.connect(item.onRightLayerChange)
|
|
item.rightLayer = widget.itemData(widget.currentIndex())
|
|
item.updatePredicates()
|
|
if param.default:
|
|
item.setValue(param.default)
|
|
else:
|
|
item = QLineEdit()
|
|
if param.default:
|
|
item.setText(unicode(param.default))
|
|
|
|
return item
|
|
|
|
def updateDependentFields(self):
|
|
sender = self.sender()
|
|
if not isinstance(sender, QComboBox):
|
|
return
|
|
if sender.name not in self.dependentItems:
|
|
return
|
|
layer = sender.itemData(sender.currentIndex())
|
|
if not layer:
|
|
return
|
|
children = self.dependentItems[sender.name]
|
|
for child in children:
|
|
if (isinstance(child, ParameterTableField) or isinstance(
|
|
child, ParameterTableMultipleField)):
|
|
widget = self.valueItems[child.name]
|
|
widget.clear()
|
|
if (self.alg.getParameterFromName(child.name).optional and
|
|
not isinstance(child, ParameterTableMultipleField)):
|
|
widget.addItem(self.tr('[not set]'))
|
|
widget.addItems(
|
|
self.getFields(layer, self.alg.getParameterFromName(
|
|
child.name).datatype))
|
|
if isinstance(child, OutputVector):
|
|
child.base_layer = layer
|
|
|
|
def getFields(self, layer, datatype):
|
|
fieldTypes = []
|
|
if datatype == ParameterTableField.DATA_TYPE_STRING:
|
|
fieldTypes = [QVariant.String]
|
|
elif datatype == ParameterTableField.DATA_TYPE_NUMBER:
|
|
fieldTypes = [QVariant.Int, QVariant.Double, QVariant.LongLong,
|
|
QVariant.UInt, QVariant.ULongLong]
|
|
|
|
fieldNames = set()
|
|
for field in layer.fields():
|
|
if not fieldTypes or field.type() in fieldTypes:
|
|
fieldNames.add(unicode(field.name()))
|
|
return sorted(list(fieldNames), cmp=locale.strcoll)
|
|
|
|
def somethingDependsOnThisParameter(self, parent):
|
|
for param in self.alg.parameters:
|
|
if isinstance(param, (ParameterTableField,
|
|
ParameterTableMultipleField)):
|
|
if param.parent == parent.name:
|
|
return True
|
|
for output in self.alg.outputs:
|
|
if isinstance(output, OutputVector):
|
|
if output.base_layer == parent.name:
|
|
return True
|
|
return False
|