Automatically handle adding data defined button for dynamic properties

Also exposes this capability to modeler - so that model algorithms
can use data defined parameters within their child algorithms.

TODO:
- tests
- setting the associated vector layer
This commit is contained in:
Nyall Dawson 2018-08-31 16:36:18 +10:00
parent a717b85e2e
commit 70c1680754
10 changed files with 109 additions and 32 deletions

View File

@ -92,22 +92,21 @@ Returns the current wrapped label, if any.
Returns the parameter definition associated with this wrapper.
%End
virtual void setWidgetValue( const QVariant &value, const QgsProcessingContext &context ) = 0;
void setParameterValue( const QVariant &value, const QgsProcessingContext &context );
%Docstring
Sets the current ``value`` for the parameter.
The ``context`` argument is used to specify the wider Processing context which the
current value is associated with.
.. seealso:: :py:func:`value`
.. seealso:: :py:func:`parameterValue`
%End
virtual QVariant value() const = 0;
QVariant parameterValue() const;
%Docstring
Returns the current value of the parameter.
.. seealso:: :py:func:`setWidgetValue`
.. seealso:: :py:func:`setParameterValue`
%End
virtual void postInitialize( const QList< QgsAbstractProcessingParameterWidgetWrapper * > &wrappers );
@ -137,6 +136,23 @@ label should be shown for the parameter's widget (i.e. the label is embedded ins
widget itself).
.. seealso:: :py:func:`createWidget`
%End
virtual void setWidgetValue( const QVariant &value, const QgsProcessingContext &context ) = 0;
%Docstring
Sets the current ``value`` for the parameter to show in the widget.
The ``context`` argument is used to specify the wider Processing context which the
current value is associated with.
.. seealso:: :py:func:`widgetValue`
%End
virtual QVariant widgetValue() const = 0;
%Docstring
Returns the current value of the parameter.
.. seealso:: :py:func:`setWidgetValue`
%End
};

View File

@ -110,7 +110,7 @@ class AlgorithmDialog(QgsProcessingAlgorithmDialogBase):
if widget is None:
continue
value = wrapper.value()
value = wrapper.parameterValue()
parameters[param.name()] = value
if not param.checkValueIsAcceptable(value):

View File

@ -219,7 +219,7 @@ class ParametersPanel(BASE, WIDGET):
value = parameters[param.name()]
wrapper = self.wrappers[param.name()]
wrapper.setWidgetValue(value, context)
wrapper.setParameterValue(value, context)
else:
dest_widget = self.outputWidgets[param.name()]
dest_widget.setValue(parameters[param.name()])

View File

@ -202,6 +202,12 @@ class WidgetWrapper(QgsAbstractProcessingParameterWidgetWrapper):
def setValue(self, value):
pass
def value(self):
return None
def widgetValue(self):
return self.value()
def setWidgetValue(self, value, context):
self.setValue(value)

View File

@ -145,7 +145,7 @@ QgsProcessingModelChildParameterSource QgsProcessingModelerParameterWidget::valu
switch ( mStackedWidget->currentIndex() )
{
case 0:
return QgsProcessingModelChildParameterSource::fromStaticValue( mStaticWidgetWrapper->value() );
return QgsProcessingModelChildParameterSource::fromStaticValue( mStaticWidgetWrapper->parameterValue() );
case 1:
return QgsProcessingModelChildParameterSource::fromExpression( mExpressionWidget->expression() );
@ -238,7 +238,7 @@ void QgsProcessingModelerParameterWidget::setSourceType( QgsProcessingModelChild
void QgsProcessingModelerParameterWidget::updateUi()
{
mStaticWidgetWrapper->setWidgetValue( mStaticValue, mContext );
mStaticWidgetWrapper->setParameterValue( mStaticValue, mContext );
mExpressionWidget->setExpression( mExpression );

View File

@ -19,8 +19,9 @@
#include "qgsprocessingwidgetwrapper.h"
#include "qgsprocessingparameters.h"
#include "qgsprocessingmodelerwidget.h"
#include "qgspropertyoverridebutton.h"
#include <QLabel>
#include <QHBoxLayout>
QgsAbstractProcessingParameterWidgetWrapper::QgsAbstractProcessingParameterWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QObject *parent )
: QObject( parent )
@ -40,9 +41,25 @@ QWidget *QgsAbstractProcessingParameterWidgetWrapper::createWrappedWidget( const
return mWidget;
mWidget = createWidget();
QWidget *wrappedWidget = mWidget;
if ( mType != QgsProcessingGui::Batch && mParameterDefinition->isDynamic() )
{
QHBoxLayout *hLayout = new QHBoxLayout();
hLayout->setMargin( 0 );
hLayout->setContentsMargins( 0, 0, 0, 0 );
hLayout->addWidget( mWidget, 1 );
mPropertyButton = new QgsPropertyOverrideButton();
hLayout->addWidget( mPropertyButton );
mPropertyButton->init( 0, QgsProperty(), mParameterDefinition->dynamicPropertyDefinition() );
mPropertyButton->registerEnabledWidget( mWidget, false );
wrappedWidget = new QWidget();
wrappedWidget->setLayout( hLayout );
}
setWidgetValue( mParameterDefinition->defaultValue(), context );
return mWidget;
return wrappedWidget;
}
QLabel *QgsAbstractProcessingParameterWidgetWrapper::createWrappedLabel()
@ -69,6 +86,26 @@ const QgsProcessingParameterDefinition *QgsAbstractProcessingParameterWidgetWrap
return mParameterDefinition;
}
void QgsAbstractProcessingParameterWidgetWrapper::setParameterValue( const QVariant &value, const QgsProcessingContext &context )
{
if ( mPropertyButton && value.canConvert< QgsProperty >() )
{
mPropertyButton->setToProperty( value.value< QgsProperty >() );
}
else
{
setWidgetValue( value, context );
}
}
QVariant QgsAbstractProcessingParameterWidgetWrapper::parameterValue() const
{
if ( mPropertyButton && mPropertyButton->isActive() )
return mPropertyButton->toProperty();
else
return widgetValue();
}
QLabel *QgsAbstractProcessingParameterWidgetWrapper::createLabel()
{
switch ( mType )

View File

@ -30,6 +30,7 @@ class QgsProcessingContext;
class QgsProcessingModelerParameterWidget;
class QgsProcessingModelAlgorithm;
class QLabel;
class QgsPropertyOverrideButton;
/**
* \class QgsAbstractProcessingParameterWidgetWrapper
@ -111,24 +112,22 @@ class GUI_EXPORT QgsAbstractProcessingParameterWidgetWrapper : public QObject
*/
const QgsProcessingParameterDefinition *parameterDefinition() const;
// TODO QGIS 4.0 - rename to setValue, avoid conflict with Python WidgetWrapper method
/**
* Sets the current \a value for the parameter.
*
* The \a context argument is used to specify the wider Processing context which the
* current value is associated with.
*
* \see value()
* \see parameterValue()
*/
virtual void setWidgetValue( const QVariant &value, const QgsProcessingContext &context ) = 0;
void setParameterValue( const QVariant &value, const QgsProcessingContext &context );
/**
* Returns the current value of the parameter.
*
* \see setWidgetValue()
* \see setParameterValue()
*/
virtual QVariant value() const = 0;
QVariant parameterValue() const;
/**
* Called after all wrappers have been created within a particular dialog or context,
@ -159,12 +158,30 @@ class GUI_EXPORT QgsAbstractProcessingParameterWidgetWrapper : public QObject
*/
virtual QLabel *createLabel() SIP_FACTORY;
/**
* Sets the current \a value for the parameter to show in the widget.
*
* The \a context argument is used to specify the wider Processing context which the
* current value is associated with.
*
* \see widgetValue()
*/
virtual void setWidgetValue( const QVariant &value, const QgsProcessingContext &context ) = 0;
/**
* Returns the current value of the parameter.
*
* \see setWidgetValue()
*/
virtual QVariant widgetValue() const = 0;
private:
QgsProcessingGui::WidgetType mType = QgsProcessingGui::Standard;
const QgsProcessingParameterDefinition *mParameterDefinition = nullptr;
QPointer< QWidget > mWidget;
QPointer< QgsPropertyOverrideButton > mPropertyButton;
QPointer< QLabel > mLabel;
};

View File

@ -92,7 +92,7 @@ void QgsProcessingBooleanWidgetWrapper::setWidgetValue( const QVariant &value, c
}
}
QVariant QgsProcessingBooleanWidgetWrapper::value() const
QVariant QgsProcessingBooleanWidgetWrapper::widgetValue() const
{
switch ( type() )
{

View File

@ -41,12 +41,11 @@ class GUI_EXPORT QgsProcessingBooleanWidgetWrapper : public QgsAbstractProcessin
// QgsProcessingParameterWidgetWrapper interface
QWidget *createWidget() override SIP_FACTORY;
QLabel *createLabel() override SIP_FACTORY;
protected:
void setWidgetValue( const QVariant &value, const QgsProcessingContext &context ) override;
QVariant value() const override;
protected:
protected:
QVariant widgetValue() const override;
QStringList compatibleParameterTypes() const override;
@ -58,6 +57,8 @@ class GUI_EXPORT QgsProcessingBooleanWidgetWrapper : public QgsAbstractProcessin
QCheckBox *mCheckBox = nullptr;
QComboBox *mComboBox = nullptr;
friend class TestProcessingGui;
};
///@endcond PRIVATE

View File

@ -79,7 +79,7 @@ class TestWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper
{
}
QVariant value() const override
QVariant widgetValue() const override
{
return QVariant();
}
@ -286,12 +286,12 @@ void TestProcessingGui::testWrapperGeneral()
param = TestParamType( QStringLiteral( "boolean" ), QStringLiteral( "bool" ), true );
QgsProcessingBooleanWidgetWrapper trueDefault( &param );
w = trueDefault.createWrappedWidget( context );
QVERIFY( trueDefault.value().toBool() );
QVERIFY( trueDefault.widgetValue().toBool() );
delete w;
param = TestParamType( QStringLiteral( "boolean" ), QStringLiteral( "bool" ), false );
QgsProcessingBooleanWidgetWrapper falseDefault( &param );
w = falseDefault.createWrappedWidget( context );
QVERIFY( !falseDefault.value().toBool() );
QVERIFY( !falseDefault.widgetValue().toBool() );
delete w;
}
@ -406,10 +406,10 @@ void TestProcessingGui::testBooleanWrapper()
QgsProcessingContext context;
QWidget *w = wrapper.createWrappedWidget( context );
wrapper.setWidgetValue( true, context );
QVERIFY( wrapper.value().toBool() );
QVERIFY( wrapper.widgetValue().toBool() );
QVERIFY( static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
wrapper.setWidgetValue( false, context );
QVERIFY( !wrapper.value().toBool() );
QVERIFY( !wrapper.widgetValue().toBool() );
QVERIFY( !static_cast< QCheckBox * >( wrapper.wrappedWidget() )->isChecked() );
// should be no label in standard mode
@ -422,10 +422,10 @@ void TestProcessingGui::testBooleanWrapper()
w = wrapperB.createWrappedWidget( context );
wrapperB.setWidgetValue( true, context );
QVERIFY( wrapperB.value().toBool() );
QVERIFY( wrapperB.widgetValue().toBool() );
QVERIFY( static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
wrapperB.setWidgetValue( false, context );
QVERIFY( !wrapperB.value().toBool() );
QVERIFY( !wrapperB.widgetValue().toBool() );
QVERIFY( !static_cast< QComboBox * >( wrapperB.wrappedWidget() )->currentData().toBool() );
// should be no label in batch mode
@ -437,10 +437,10 @@ void TestProcessingGui::testBooleanWrapper()
w = wrapperM.createWrappedWidget( context );
wrapperM.setWidgetValue( true, context );
QVERIFY( wrapperM.value().toBool() );
QVERIFY( wrapperM.widgetValue().toBool() );
QVERIFY( static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
wrapperM.setWidgetValue( false, context );
QVERIFY( !wrapperM.value().toBool() );
QVERIFY( !wrapperM.widgetValue().toBool() );
QVERIFY( !static_cast< QComboBox * >( wrapperM.wrappedWidget() )->currentData().toBool() );
// should be a label in modeler mode