Skip to content
Permalink
Browse files

Merge pull request #5171 from nyalldawson/processing_selectioncheckboxes

[processing] Add useCheckBoxes option to EnumWidgetWrapper
  • Loading branch information
nyalldawson committed Sep 16, 2017
2 parents 7a1b9f9 + 085687d commit f9bc9259c08bd60788b69063a922555781de3c48
@@ -80,6 +80,11 @@ def initAlgorithm(self, config=None):
self.tr('Input layer')))
self.addParameter(QgsProcessingParameterEnum(self.METHOD,
self.tr('Method'), self.methods))
self.parameterDefinition(self.METHOD).setMetadata({
'widget_wrapper': {
'class': 'processing.gui.wrappers.EnumWidgetWrapper',
'useCheckBoxes': True,
'columns': 3}})

self.addParameter(QgsProcessingParameterFeatureSink(self.VALID_OUTPUT, self.tr('Valid output'), QgsProcessing.TypeVectorAnyGeometry, '', True))
self.addOutput(QgsProcessingOutputNumber(self.VALID_COUNT, self.tr('Count of valid features')))
@@ -96,10 +96,17 @@ def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.JOIN,
self.tr('Join layer'),
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterEnum(self.PREDICATE,
self.tr('Geometric predicate'),
options=[p[1] for p in self.predicates],
allowMultiple=True, defaultValue=[0]))

predicate = QgsProcessingParameterEnum(self.PREDICATE,
self.tr('Geometric predicate'),
options=[p[1] for p in self.predicates],
allowMultiple=True, defaultValue=[0])
predicate.setMetadata({
'widget_wrapper': {
'class': 'processing.gui.wrappers.EnumWidgetWrapper',
'useCheckBoxes': True,
'columns': 2}})
self.addParameter(predicate)
self.addParameter(QgsProcessingParameterField(self.JOIN_FIELDS,
self.tr('Fields to add (leave empty to use all fields)'),
parentLayerParameterName=self.JOIN,
@@ -110,10 +110,16 @@ def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.JOIN,
self.tr('Join layer'),
[QgsProcessing.TypeVectorAnyGeometry]))
self.addParameter(QgsProcessingParameterEnum(self.PREDICATE,
self.tr('Geometric predicate'),
options=[p[1] for p in self.predicates],
allowMultiple=True, defaultValue=[0]))
predicate = QgsProcessingParameterEnum(self.PREDICATE,
self.tr('Geometric predicate'),
options=[p[1] for p in self.predicates],
allowMultiple=True, defaultValue=[0])
predicate.setMetadata({
'widget_wrapper': {
'class': 'processing.gui.wrappers.EnumWidgetWrapper',
'useCheckBoxes': True,
'columns': 2}})
self.addParameter(predicate)
self.addParameter(QgsProcessingParameterField(self.JOIN_FIELDS,
self.tr('Fields to summarise (leave empty to use all fields)'),
parentLayerParameterName=self.JOIN,
@@ -371,8 +371,8 @@ def __init__(self, name='', description='', optional=False, showSublayersDialog=
class ParameterSelection(Parameter):

def __init__(self, name='', description='', options=[], default=None, isSource=False,
multiple=False, optional=False):
Parameter.__init__(self, name, description, default, optional)
multiple=False, optional=False, metadata={}):
Parameter.__init__(self, name, description, default, optional, metadata)
self.multiple = multiple
isSource = parseBool(isSource)
self.options = options
@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-

"""
***************************************************************************
CheckBoxesPanel.py
---------------------
Date : January 2015
Copyright : (C) 2015 by Arnaud Morvan
Email : arnaud dot morvan at camptocamp dot com
Contributors : Arnaud Morvan
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
from builtins import range

__author__ = 'Arnaud Morvan'
__date__ = 'January 2015'
__copyright__ = '(C) 2015, Arnaud Morvan'

# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'

from qgis.PyQt.QtCore import Qt
from qgis.PyQt.QtWidgets import (
QCheckBox,
QRadioButton,
QGridLayout,
QButtonGroup,
QSizePolicy,
QSpacerItem,
QWidget,
QMenu,
QAction
)
from qgis.PyQt.QtGui import QCursor


class CheckboxesPanel(QWidget):

def __init__(self, options, multiple, columns=2, parent=None):
super(CheckboxesPanel, self).__init__(parent)

self._options = []
for i, option in enumerate(options):
if isinstance(option, str):
self._options.append((i, option))
else:
self.options.append(option)
self._multiple = multiple
self._buttons = []
rows = len(options) / columns

self._buttonGroup = QButtonGroup()
self._buttonGroup.setExclusive(not multiple)
layout = QGridLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setMargin(0)
for i, (v, t) in enumerate(self._options):
if multiple:
button = QCheckBox(t)
else:
button = QRadioButton(t)
self._buttons.append((v, button))
self._buttonGroup.addButton(button, i)
layout.addWidget(button, i % rows, i / rows)
layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Minimum),
0, columns)
self.setLayout(layout)

if multiple:
self.setContextMenuPolicy(Qt.CustomContextMenu)
self.customContextMenuRequested.connect(self.showPopupMenu)

def showPopupMenu(self):
popup_menu = QMenu()
select_all_action = QAction(self.tr('Select All'), popup_menu)
select_all_action.triggered.connect(self.selectAll)
clear_all_action = QAction(self.tr('Clear Selection'), popup_menu)
clear_all_action.triggered.connect(self.deselectAll)
popup_menu.addAction(select_all_action)
popup_menu.addAction(clear_all_action)
popup_menu.exec_(QCursor.pos())

def selectAll(self):
for (v, button) in self._buttons:
button.setChecked(True)

def deselectAll(self):
for (v, button) in self._buttons:
button.setChecked(False)

def value(self):
if self._multiple:
value = []
for (v, checkbox) in self._buttons:
if checkbox.isChecked():
value.append(v)
return value
else:
return self._options[self._buttonGroup.checkedId()][0]

def setValue(self, value):
if self._multiple:
for (v, button) in self._buttons:
if v in value:
button.setChecked(True)
else:
for v, button in self._buttons:
if v == value:
button.setChecked(True)
@@ -118,6 +118,7 @@
from processing.core.outputs import (OutputFile, OutputRaster, OutputVector,
OutputString, OutputTable, OutputExtent)
from processing.tools import dataobjects
from processing.gui.CheckboxesPanel import CheckboxesPanel
from processing.gui.MultipleInputPanel import MultipleInputPanel
from processing.gui.BatchInputSelectionPanel import BatchInputSelectionPanel
from processing.gui.FixedTablePanel import FixedTablePanel
@@ -803,7 +804,12 @@ def selectFile(self):

class EnumWidgetWrapper(WidgetWrapper):

def createWidget(self):
def createWidget(self, useCheckBoxes=False, columns=1):
self._useCheckBoxes = useCheckBoxes
if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
return CheckboxesPanel(options=self.param.options(),
multiple=self.param.allowMultiple(),
columns=columns)
if self.param.allowMultiple():
return MultipleInputPanel(options=self.param.options())
else:
@@ -815,12 +821,17 @@ def createWidget(self):
return widget

def setValue(self, value):
if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
self.widget.setValue(value)
return
if self.param.allowMultiple():
self.widget.setSelectedItems(value)
else:
self.widget.setCurrentIndex(self.widget.findData(value))

def value(self):
if self._useCheckBoxes and not self.dialogType == DIALOG_BATCH:
return self.widget.value()
if self.param.allowMultiple():
return self.widget.selectedoptions
else:
@@ -1356,12 +1356,7 @@ void QgsSelectByLocationAlgorithm::initAlgorithm( const QVariantMap & )

addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "INPUT" ), QObject::tr( "Select features from" ),
QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );


addParameter( new QgsProcessingParameterEnum( QStringLiteral( "PREDICATE" ),
QObject::tr( "Where the features are (geometric predicate)" ),
predicateOptionsList(), true, QVariant::fromValue( QList< int >() << 0 ) ) );

addPredicateParameter();
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INTERSECT" ),
QObject::tr( "By comparing to the features from" ),
QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
@@ -1529,6 +1524,23 @@ void QgsLocationBasedAlgorithm::process( QgsFeatureSource *targetSource,
}
}

void QgsLocationBasedAlgorithm::addPredicateParameter()
{
std::unique_ptr< QgsProcessingParameterEnum > predicateParam( new QgsProcessingParameterEnum( QStringLiteral( "PREDICATE" ),
QObject::tr( "Where the features (geometric predicate)" ),
predicateOptionsList(), true, QVariant::fromValue( QList< int >() << 0 ) ) );

QVariantMap predicateMetadata;
QVariantMap widgetMetadata;
widgetMetadata.insert( QStringLiteral( "class" ), QStringLiteral( "processing.gui.wrappers.EnumWidgetWrapper" ) );
widgetMetadata.insert( QStringLiteral( "useCheckBoxes" ), true );
widgetMetadata.insert( QStringLiteral( "columns" ), 2 );
predicateMetadata.insert( QStringLiteral( "widget_wrapper" ), widgetMetadata );
predicateParam->setMetadata( predicateMetadata );

addParameter( predicateParam.release() );
}

QgsLocationBasedAlgorithm::Predicate QgsLocationBasedAlgorithm::reversePredicate( QgsLocationBasedAlgorithm::Predicate predicate ) const
{
switch ( predicate )
@@ -1556,14 +1568,14 @@ QgsLocationBasedAlgorithm::Predicate QgsLocationBasedAlgorithm::reversePredicate

QStringList QgsLocationBasedAlgorithm::predicateOptionsList() const
{
return QStringList() << QObject::tr( "intersects" )
<< QObject::tr( "contains" )
<< QObject::tr( "is disjoint" )
<< QObject::tr( "equals" )
<< QObject::tr( "touches" )
<< QObject::tr( "overlaps" )
<< QObject::tr( "within" )
<< QObject::tr( "crosses" );
return QStringList() << QObject::tr( "intersect" )
<< QObject::tr( "contain" )
<< QObject::tr( "disjoint" )
<< QObject::tr( "equal" )
<< QObject::tr( "touch" )
<< QObject::tr( "overlap" )
<< QObject::tr( "are within" )
<< QObject::tr( "cross" );
}


@@ -1572,11 +1584,7 @@ void QgsExtractByLocationAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterVectorLayer( QStringLiteral( "INPUT" ), QObject::tr( "Extract features from" ),
QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );

addParameter( new QgsProcessingParameterEnum( QStringLiteral( "PREDICATE" ),
QObject::tr( "Where the features are (geometric predicate)" ),
predicateOptionsList(), true, QVariant::fromValue( QList< int >() << 0 ) ) );

addPredicateParameter();
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INTERSECT" ),
QObject::tr( "By comparing to the features from" ),
QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
@@ -504,6 +504,7 @@ class QgsLocationBasedAlgorithm : public QgsProcessingAlgorithm
Crosses,
};

void addPredicateParameter();
Predicate reversePredicate( Predicate predicate ) const;
QStringList predicateOptionsList() const;
void process( QgsFeatureSource *targetSource, QgsFeatureSource *intersectSource, const QList<int> &selectedPredicates, const std::function< void( const QgsFeature & )> &handleFeatureFunction, bool onlyRequireTargetIds, QgsFeedback *feedback );
@@ -1988,7 +1988,11 @@ bool QgsProcessingParameterEnum::checkValueIsAcceptable( const QVariant &input,
if ( !mAllowMultiple )
return false;

Q_FOREACH ( const QVariant &val, input.toList() )
const QVariantList values = input.toList();
if ( values.empty() && !( mFlags & FlagOptional ) )
return false;

for ( const QVariant &val : values )
{
bool ok = false;
int res = val.toInt( &ok );
@@ -2784,6 +2784,7 @@ void TestQgsProcessing::parameterEnum()
QVERIFY( def->checkValueIsAcceptable( "1" ) );
QVERIFY( !def->checkValueIsAcceptable( "1,2" ) );
QVERIFY( def->checkValueIsAcceptable( 0 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << 1 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" ) );
QVERIFY( !def->checkValueIsAcceptable( 15 ) );
@@ -2853,6 +2854,7 @@ void TestQgsProcessing::parameterEnum()
QVERIFY( def->checkValueIsAcceptable( "1" ) );
QVERIFY( def->checkValueIsAcceptable( "1,2" ) );
QVERIFY( def->checkValueIsAcceptable( 0 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() ) ); // since non-optional, empty list not allowed
QVERIFY( def->checkValueIsAcceptable( QVariantList() << 1 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" ) );
QVERIFY( !def->checkValueIsAcceptable( 15 ) );
@@ -2893,6 +2895,7 @@ void TestQgsProcessing::parameterEnum()
QVERIFY( def->checkValueIsAcceptable( "1" ) );
QVERIFY( !def->checkValueIsAcceptable( "1,2" ) );
QVERIFY( def->checkValueIsAcceptable( 0 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << 1 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" ) );
QVERIFY( !def->checkValueIsAcceptable( 15 ) );
@@ -2925,6 +2928,7 @@ void TestQgsProcessing::parameterEnum()
QVERIFY( def->checkValueIsAcceptable( "1" ) );
QVERIFY( def->checkValueIsAcceptable( "1,2" ) );
QVERIFY( def->checkValueIsAcceptable( 0 ) );
QVERIFY( def->checkValueIsAcceptable( QVariantList() ) );
QVERIFY( def->checkValueIsAcceptable( QVariantList() << 1 ) );
QVERIFY( !def->checkValueIsAcceptable( QVariantList() << "a" ) );
QVERIFY( !def->checkValueIsAcceptable( 15 ) );

0 comments on commit f9bc925

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