From 41fb4df77f6e2b48cda89e25516a31ad7c0c071f Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 24 Mar 2020 12:27:59 +1000 Subject: [PATCH] [processing] Move iterate button to c++ --- images/images.qrc | 1 + images/themes/default/mIconIterate.svg | 61 ++++++++++++++++++ python/plugins/processing/gui/wrappers.py | 25 +------ python/plugins/processing/images/iterate.png | Bin 549 -> 0 bytes .../qgsprocessingmaplayercombobox.cpp | 40 ++++++++++-- .../qgsprocessingmaplayercombobox.h | 1 + tests/src/gui/testprocessinggui.cpp | 12 +++- 7 files changed, 112 insertions(+), 28 deletions(-) create mode 100644 images/themes/default/mIconIterate.svg delete mode 100644 python/plugins/processing/images/iterate.png diff --git a/images/images.qrc b/images/images.qrc index 06a9872019b..45f9503dbcf 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -833,6 +833,7 @@ themes/default/temporal_navigation/rewindToStart.svg themes/default/temporal_navigation/skipToEnd.svg themes/default/temporal_navigation/pause.svg + themes/default/mIconIterate.svg qgis_tips/symbol_levels.png diff --git a/images/themes/default/mIconIterate.svg b/images/themes/default/mIconIterate.svg new file mode 100644 index 00000000000..5ad34d826e6 --- /dev/null +++ b/images/themes/default/mIconIterate.svg @@ -0,0 +1,61 @@ + + + + + + image/svg+xml + + + + + + + + + + diff --git a/python/plugins/processing/gui/wrappers.py b/python/plugins/processing/gui/wrappers.py index b42ec46895d..0d72828fb0a 100755 --- a/python/plugins/processing/gui/wrappers.py +++ b/python/plugins/processing/gui/wrappers.py @@ -1145,23 +1145,7 @@ class FeatureSourceWidgetWrapper(WidgetWrapper): self.combo.valueChanged.connect(lambda: self.widgetValueHasChanged.emit(self)) self.combo.triggerFileSelection.connect(self.selectFile) - layout = QHBoxLayout() - layout.setSpacing(6) - layout.setMargin(0) - layout.addWidget(self.combo) - self.iterate_button = QToolButton() - icon = QIcon(os.path.join(pluginPath, 'images', 'iterate.png')) - self.iterate_button.setIcon(icon) - self.iterate_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) - self.iterate_button.setToolTip( - self.tr('Iterate over this layer, creating a separate output for every feature in the layer')) - self.iterate_button.setCheckable(True) - layout.addWidget(self.iterate_button) - layout.setAlignment(self.iterate_button, Qt.AlignTop) - - widget = QWidget() - widget.setLayout(layout) - return widget + return self.combo elif self.dialogType == DIALOG_BATCH: widget = BatchInputSelectionPanel(self.parameterDefinition(), self.row, self.col, self.dialog) @@ -1225,12 +1209,7 @@ class FeatureSourceWidgetWrapper(WidgetWrapper): def value(self): if self.dialogType == DIALOG_STANDARD: - v = self.combo.value() - if self.iterate_button.isChecked(): - if not isinstance(v, QgsProcessingFeatureSourceDefinition): - v = QgsProcessingFeatureSourceDefinition(v) - v.flags = v.flags | QgsProcessingFeatureSourceDefinition.Flag.FlagCreateIndividualOutputPerInputFeature - return v + return self.combo.value() elif self.dialogType == DIALOG_BATCH: return self.widget.getValue() else: diff --git a/python/plugins/processing/images/iterate.png b/python/plugins/processing/images/iterate.png deleted file mode 100644 index 384147dcab298367c131e1e05d5c80ced7977dcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 549 zcmV+=0^0qFP)io7%vb+X+>>8L=YS>K-9E}9gL|s zqSCY_+V;K-S>8Z2F^U=+f1F=uuWy~b&fY8ltp7QzCjlq|1lhSQp*y}cL%P`j;$s~x zUK5h{0=o9v*ovLjkl|Pj_n8Gg+J)7>PS}2$F}T%*x}{g4>V*n+T!5Srn@%bCX*U+n zZSee=$MU%y_TSTRhAkNS+6}&~By=l4{=Jpd2UYO?i@CbOR*VLe&}{d^`r{q!zh*GY zyrje5f|AL6@&-V*C8izW_l&C}THNFlL_{7wRpYLts^-fh<`W}K$9m`j!zeQ5(l-Fo z&y65Hi6B|8L8Dgy(F$LAdB?MIsW%(#m^>MaLO8k?xc3`{u9sIuWmAQe%uirEsKwYJ zg=|g6-2f(O@aIYq6Bl@jO`M2sR}Ias63Q>#cs`U$#{~$S73f?i@Y*LqsW~4lOZ6}u zjzWK+0kx+_wS|XgeaYml0D+?%vNeL~)qshh9>yaIhJz8PclsHz3Jne+(t49Zap!9~}=DHtq?c0>2>O*BzoUBM--#ND4+2~O^l7^}#nc}a00000NkvXXu0mjfV)6Oc diff --git a/src/gui/processing/qgsprocessingmaplayercombobox.cpp b/src/gui/processing/qgsprocessingmaplayercombobox.cpp index 58fadea5198..c71cb6f12fc 100644 --- a/src/gui/processing/qgsprocessingmaplayercombobox.cpp +++ b/src/gui/processing/qgsprocessingmaplayercombobox.cpp @@ -20,6 +20,8 @@ #include "qgssettings.h" #include "qgsvectorlayer.h" #include "qgsfeatureid.h" +#include "qgsapplication.h" +#include "qgsguiutils.h" #include #include #include @@ -48,6 +50,24 @@ QgsProcessingMapLayerComboBox::QgsProcessingMapLayerComboBox( const QgsProcessin layout->addWidget( mSelectButton ); layout->setAlignment( mSelectButton, Qt::AlignTop ); + if ( mParameter->type() == QgsProcessingParameterFeatureSource::typeName() ) + { + mIterateButton = new QToolButton(); + mIterateButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "mIconIterate.svg" ) ) ); + mIterateButton->setToolTip( tr( "Iterate over this layer, creating a separate output for every feature in the layer" ) ); + mIterateButton->setCheckable( true ); + mIterateButton->setAutoRaise( true ); + + int iconSize = QgsGuiUtils::scaleIconSize( 24 ); + + // button width is 1.25 * icon size, height 1.1 * icon size. But we round to ensure even pixel sizes for equal margins + mIterateButton->setFixedSize( 2 * static_cast< int >( 1.25 * iconSize / 2.0 ), 2 * static_cast< int >( iconSize * 1.1 / 2.0 ) ); + + mIterateButton->setIconSize( QSize( iconSize, iconSize ) ); + + layout->addWidget( mIterateButton ); + } + QVBoxLayout *vl = new QVBoxLayout(); vl->setMargin( 0 ); vl->setContentsMargins( 0, 0, 0, 0 ); @@ -164,11 +184,13 @@ void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessi QVariant val = value; bool found = false; bool selectedOnly = false; + bool iterate = false; if ( val.canConvert() ) { QgsProcessingFeatureSourceDefinition fromVar = qvariant_cast( val ); val = fromVar.source; selectedOnly = fromVar.selectedFeaturesOnly; + iterate = fromVar.flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature; } if ( val.canConvert() ) @@ -210,6 +232,11 @@ void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessi mUseSelectionCheckBox->setChecked( false ); mUseSelectionCheckBox->setEnabled( false ); } + + if ( mIterateButton ) + { + mIterateButton->setChecked( iterate ); + } } mBlockChangedSignal--; if ( changed ) @@ -224,6 +251,9 @@ void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessi mUseSelectionCheckBox->setChecked( false ); mUseSelectionCheckBox->setEnabled( false ); } + if ( mIterateButton ) + mIterateButton->setChecked( iterate ); + if ( !string.isEmpty() ) { mBlockChangedSignal++; @@ -247,10 +277,12 @@ void QgsProcessingMapLayerComboBox::setValue( const QVariant &value, QgsProcessi QVariant QgsProcessingMapLayerComboBox::value() const { + const bool iterate = mIterateButton && mIterateButton->isChecked(); + const bool selectedOnly = mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked(); if ( QgsMapLayer *layer = mCombo->currentLayer() ) { - if ( mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked() ) - return QgsProcessingFeatureSourceDefinition( layer->id(), true ); + if ( selectedOnly || iterate ) + return QgsProcessingFeatureSourceDefinition( layer->id(), selectedOnly, -1, iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() ); else return layer->id(); } @@ -258,8 +290,8 @@ QVariant QgsProcessingMapLayerComboBox::value() const { if ( !mCombo->currentText().isEmpty() ) { - if ( mUseSelectionCheckBox && mUseSelectionCheckBox->isChecked() ) - return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), true ); + if ( selectedOnly || iterate ) + return QgsProcessingFeatureSourceDefinition( mCombo->currentText(), selectedOnly, -1, iterate ? QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature : QgsProcessingFeatureSourceDefinition::Flags() ); else return mCombo->currentText(); } diff --git a/src/gui/processing/qgsprocessingmaplayercombobox.h b/src/gui/processing/qgsprocessingmaplayercombobox.h index 3fc14f4aba1..5bc0cb8fed1 100644 --- a/src/gui/processing/qgsprocessingmaplayercombobox.h +++ b/src/gui/processing/qgsprocessingmaplayercombobox.h @@ -120,6 +120,7 @@ class GUI_EXPORT QgsProcessingMapLayerComboBox : public QWidget std::unique_ptr< QgsProcessingParameterDefinition > mParameter; QgsMapLayerComboBox *mCombo = nullptr; QToolButton *mSelectButton = nullptr; + QToolButton *mIterateButton = nullptr; QCheckBox *mUseSelectionCheckBox = nullptr; bool mDragActive = false; QPointer< QgsMapLayer> mPrevLayer; diff --git a/tests/src/gui/testprocessinggui.cpp b/tests/src/gui/testprocessinggui.cpp index bb29e301193..dde91219d17 100644 --- a/tests/src/gui/testprocessinggui.cpp +++ b/tests/src/gui/testprocessinggui.cpp @@ -4035,12 +4035,22 @@ void TestProcessingGui::mapLayerComboBox() vl->selectAll(); sourceDef = QgsProcessingFeatureSourceDefinition( vl->id(), true ); combo->setValue( sourceDef, context ); - // except "selected only" state to remain + // expect "selected only" state to remain QVERIFY( combo->value().canConvert< QgsProcessingFeatureSourceDefinition >() ); QCOMPARE( combo->value().value< QgsProcessingFeatureSourceDefinition >().source.staticValue().toString(), vl->id() ); QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().selectedFeaturesOnly ); QVERIFY( combo->currentText().startsWith( vl->name() ) ); QCOMPARE( spy.count(), 13 ); + + // iterate over features + QVERIFY( !( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature ) ); + sourceDef.flags |= QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature; + combo->setValue( sourceDef, context ); + QVERIFY( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature ); + sourceDef.flags = nullptr; + combo->setValue( sourceDef, context ); + QVERIFY( !( combo->value().value< QgsProcessingFeatureSourceDefinition >().flags & QgsProcessingFeatureSourceDefinition::Flag::FlagCreateIndividualOutputPerInputFeature ) ); + combo.reset(); param.reset();