Skip to content
Permalink
Browse files

[processing] ParameterTableMultipleField type added

This adds a widget with multiple column attributes selector
  • Loading branch information
mbernasocchi authored and m-kuhn committed Jun 2, 2016
1 parent 2dea7c8 commit f9ab7223fcfbeb4979f5be31774219b116ab5f18
@@ -43,6 +43,7 @@
from processing.core.parameters import ParameterBoolean
from processing.core.parameters import ParameterSelection
from processing.core.parameters import ParameterTableField
from processing.core.parameters import ParameterTableMultipleField
from processing.core.parameters import ParameterExtent
from processing.core.parameters import ParameterCrs
from processing.core.parameters import ParameterFile
@@ -231,6 +232,15 @@ def processInputParameterToken(self, token, name):
break
if found:
param = ParameterTableField(name, desc, field)
elif token.lower().strip().startswith('multiple field'):
field = token.strip()[len('multiple field') + 1:]
found = False
for p in self.parameters:
if p.name == field:
found = True
break
if found:
param = ParameterTableMultipleField(token, desc, field)
elif token.lower().strip() == 'extent':
param = ParameterExtent(name, desc)
elif token.lower().strip() == 'point':
@@ -401,7 +411,7 @@ def getImportCommands(self):
commands.append(param.name + ' = NULL')
elif isinstance(param, ParameterCrs):
commands.append(param.name + ' = "' + param.value + '"')
elif isinstance(param, (ParameterTableField, ParameterString,
elif isinstance(param, (ParameterTableField, ParameterTableMultipleField, ParameterString,
ParameterFile)):
commands.append(param.name + '="' + param.value + '"')
elif isinstance(param, (ParameterNumber, ParameterSelection)):
@@ -898,6 +898,72 @@ def getAsScriptCode(self):
return '##' + self.name + '=' + param_type + self.parent


class ParameterTableMultipleField(Parameter):
"""A parameter representing several table fields.
Its value is a string with items separated by semicolons, each of
which represents the name of each field.
In a script you can use it with
##Fields=[optional] multiple field [number|string] Parentinput
In the batch runner simply use a string with items separated by
semicolons, each of which represents the name of each field.
see algs.qgis.DeleteColumn.py for an usage example
"""

DATA_TYPE_NUMBER = 0
DATA_TYPE_STRING = 1
DATA_TYPE_ANY = -1

def __init__(self, name='', description='', parent=None, datatype=-1,
optional=False):
Parameter.__init__(self, name, description, None, optional)
self.parent = parent
self.datatype = int(datatype)

def getValueAsCommandLineParameter(self):
return '"' + unicode(self.value) + '"' if self.value is not None else unicode(None)

def setValue(self, obj):
if obj is None:
if self.optional:
self.value = None
return True
return False

if isinstance(obj, list):
if len(obj) == 0:
if self.optional:
self.value = None
return True
return False
self.value = ";".join(obj)
return True
else:
self.value = unicode(obj)
return True

def __str__(self):
return self.name + ' <' + self.__module__.split('.')[-1] + ' from ' \
+ self.parent + '>'

def dataType(self):
if self.datatype == self.DATA_TYPE_NUMBER:
return 'numeric'
elif self.datatype == self.DATA_TYPE_STRING:
return 'string'
else:
return 'any'

def getAsScriptCode(self):
param_type = ''
if self.optional:
param_type += 'optional '
param_type += 'multiple field '
return '##' + self.name + '=' + param_type + self.parent


class ParameterVector(ParameterDataObject):

VECTOR_TYPE_POINT = 0
@@ -49,6 +49,7 @@
from processing.core.parameters import ParameterFixedTable
from processing.core.parameters import ParameterRange
from processing.core.parameters import ParameterTableField
from processing.core.parameters import ParameterTableMultipleField
from processing.core.parameters import ParameterMultipleInput
from processing.core.parameters import ParameterString
from processing.core.parameters import ParameterNumber
@@ -149,10 +150,14 @@ def setParamValue(self, param, widget, alg=None):
return param.setValue(widget.table)
elif isinstance(param, ParameterRange):
return param.setValue(widget.getValue())
if isinstance(param, ParameterTableField):
elif isinstance(param, ParameterTableField):
if param.optional and widget.currentIndex() == 0:
return param.setValue(None)
return param.setValue(widget.currentText())
elif isinstance(param, ParameterTableMultipleField):
if param.optional and len(list(widget.get_selected_items())) == 0:
return param.setValue(None)
return param.setValue(list(widget.get_selected_items()))
elif isinstance(param, ParameterMultipleInput):
if param.datatype == ParameterMultipleInput.TYPE_FILE:
return param.setValue(widget.selectedoptions)
@@ -0,0 +1,218 @@
"""
allows multiple selection in a large list
Contact : marco@opengis.ch
.. note:: 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__ = 'marco@opengis.ch'
__revision__ = '$Format:%H$'
__date__ = '9/07/2013'

from PyQt4 import QtGui, QtCore, Qt


class ListMultiSelectWidget(QtGui.QGroupBox):
"""Widget to show two parallel lists and move elements between the two
usage from code:
self.myWidget = ListMultiSelectWidget(title='myTitle')
self.myLayout.insertWidget(1, self.myWidget)
usage from designer:
insert a QGroupBox in your UI file
optionally give a title to the QGroupBox
promote it to ListMultiSelectWidget
"""

selection_changed = QtCore.pyqtSignal()

def __init__(self, parent=None, title=None):
QtGui.QGroupBox.__init__(self)
self.setTitle(title)

self.selected_widget = None
self.unselected_widget = None
self._setupUI()

# connect actions
self.select_all_btn.clicked.connect(self._select_all)
self.deselect_all_btn.clicked.connect(self._deselect_all)
self.select_btn.clicked.connect(self._select)
self.deselect_btn.clicked.connect(self._deselect)

self.unselected_widget.itemDoubleClicked.connect(self._select)
self.selected_widget.itemDoubleClicked.connect(self._deselect)

def get_selected_items(self):
"""
:return list with all the selected items text
"""
return self._get_items(self.selected_widget)

def get_unselected_items(self):
"""
:return list with all the unselected items text
"""
return self._get_items(self.unselected_widget)

def add_selected_items(self, items):
"""
:param items list of strings to be added in the selected list
"""
self._add_items(self.selected_widget, items)

def add_unselected_items(self, items):
"""
:param items list of strings to be added in the unselected list
"""
self._add_items(self.unselected_widget, items)

def set_selected_items(self, items):
"""
:param items list of strings to be set as the selected list
"""
self._set_items(self.selected_widget, items)

def set_unselected_items(self, items):
"""
:param items list of strings to be set as the unselected list
"""
self._set_items(self.unselected_widget, items)

def clear(self):
"""
removes all items from selected and unselected
"""
self.set_selected_items([])
self.set_unselected_items([])

def addItem(self, item):
"""
This is for Processing
:param item: string to be added in the unselected list
"""
self.add_unselected_items([item])

def addItems(self, items):
"""
This is for Processing
:param items: list of strings to be added in the unselected list
"""
self.add_unselected_items(items)

def _get_items(self, widget):
for i in range(widget.count()):
yield widget.item(i).text()

def _set_items(self, widget, items):
widget.clear()
self._add_items(widget, items)

def _add_items(self, widget, items):
widget.addItems(items)

def _select_all(self):
self.unselected_widget.selectAll()
self._do_move(self.unselected_widget, self.selected_widget)

def _deselect_all(self):
self.selected_widget.selectAll()
self._do_move(self.selected_widget, self.unselected_widget)

def _select(self):
self._do_move(self.unselected_widget, self.selected_widget)

def _deselect(self):
self._do_move(self.selected_widget, self.unselected_widget)

def _do_move(self, fromList, toList):
for item in fromList.selectedItems():
prev_from_item = fromList.item(fromList.row(item) - 1)
toList.addItem(fromList.takeItem(fromList.row(item)))
fromList.scrollToItem(prev_from_item)
self.selection_changed.emit()

def _setupUI(self):
self.setSizePolicy(
QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Ignored)

self.setMinimumHeight(180)

self.main_horizontal_layout = QtGui.QHBoxLayout(self)

italic_font = QtGui.QFont()
italic_font.setItalic(True)

# unselected widget
self.unselected_widget = QtGui.QListWidget(self)
self._set_list_widget_defaults(self.unselected_widget)
unselected_label = QtGui.QLabel()
unselected_label.setText('Unselected')
unselected_label.setAlignment(Qt.Qt.AlignCenter)
unselected_label.setFont(italic_font)
unselected_v_layout = QtGui.QVBoxLayout()
unselected_v_layout.addWidget(unselected_label)
unselected_v_layout.addWidget(self.unselected_widget)

# selected widget
self.selected_widget = QtGui.QListWidget(self)
self._set_list_widget_defaults(self.selected_widget)
selected_label = QtGui.QLabel()
selected_label.setText('Selected')
selected_label.setAlignment(Qt.Qt.AlignCenter)
selected_label.setFont(italic_font)
selected_v_layout = QtGui.QVBoxLayout()
selected_v_layout.addWidget(selected_label)
selected_v_layout.addWidget(self.selected_widget)

# buttons
self.buttons_vertical_layout = QtGui.QVBoxLayout()
self.buttons_vertical_layout.setContentsMargins(0, -1, 0, -1)

self.select_all_btn = SmallQPushButton('>>')
self.deselect_all_btn = SmallQPushButton('<<')
self.select_btn = SmallQPushButton('>')
self.deselect_btn = SmallQPushButton('<')
self.select_btn.setToolTip('Add the selected items')
self.deselect_btn.setToolTip('Remove the selected items')
self.select_all_btn.setToolTip('Add all')
self.deselect_all_btn.setToolTip('Remove all')

# add buttons
spacer_label = QtGui.QLabel() # pragmatic way to create a spacer with
# the same height of the labels on top
# of the lists, in order to align the
# buttons with the lists.
self.buttons_vertical_layout.addWidget(spacer_label)
self.buttons_vertical_layout.addWidget(self.select_btn)
self.buttons_vertical_layout.addWidget(self.deselect_btn)
self.buttons_vertical_layout.addWidget(self.select_all_btn)
self.buttons_vertical_layout.addWidget(self.deselect_all_btn)

# add sub widgets
self.main_horizontal_layout.addLayout(unselected_v_layout)
self.main_horizontal_layout.addLayout(self.buttons_vertical_layout)
self.main_horizontal_layout.addLayout(selected_v_layout)

def _set_list_widget_defaults(self, widget):
widget.setAlternatingRowColors(True)
widget.setSortingEnabled(True)
widget.setDragEnabled(True)
widget.setDragDropMode(QtGui.QAbstractItemView.DragDrop)
widget.setDragDropOverwriteMode(False)
widget.setDefaultDropAction(QtCore.Qt.MoveAction)
widget.setSelectionMode(QtGui.QAbstractItemView.MultiSelection)


class SmallQPushButton(QtGui.QPushButton):
def __init__(self, text):
QtGui.QPushButton.__init__(self)
self.setText(text)
buttons_size_policy = QtGui.QSizePolicy(
QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
self.setSizePolicy(buttons_size_policy)
self.setMaximumSize(QtCore.QSize(30, 30))

0 comments on commit f9ab722

Please sign in to comment.
You can’t perform that action at this time.