Start on numeric wrapper

This commit is contained in:
Nyall Dawson 2018-09-19 09:29:39 +10:00
parent e85c09254c
commit c406ec3be2
3 changed files with 277 additions and 0 deletions

View File

@ -30,6 +30,7 @@ QgsProcessingGuiRegistry::QgsProcessingGuiRegistry()
addParameterWidgetFactory( new QgsProcessingBooleanWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingCrsWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingStringWidgetWrapper() );
addParameterWidgetFactory( new QgsProcessingNumericWidgetWrapper() );
}
QgsProcessingGuiRegistry::~QgsProcessingGuiRegistry()

View File

@ -19,6 +19,8 @@
#include "qgsprocessingparameters.h"
#include "qgsprocessingoutputs.h"
#include "qgsprojectionselectionwidget.h"
#include "qgsspinbox.h"
#include "qgsdoublespinbox.h"
#include <QLabel>
#include <QHBoxLayout>
#include <QCheckBox>
@ -403,4 +405,233 @@ QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingStringWidgetWrapper::c
}
//
// QgsProcessingNumericWidgetWrapper
//
QgsProcessingNumericWidgetWrapper::QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type, QWidget *parent )
: QgsAbstractProcessingParameterWidgetWrapper( parameter, type, parent )
{
}
QWidget *QgsProcessingNumericWidgetWrapper::createWidget()
{
const QgsProcessingParameterNumber *numberDef = static_cast< const QgsProcessingParameterNumber * >( parameterDefinition() );
switch ( type() )
{
case QgsProcessingGui::Standard:
case QgsProcessingGui::Modeler:
case QgsProcessingGui::Batch:
{
// lots of duplicate code here -- but there's no common interface between QSpinBox/QDoubleSpinBox which would allow us to avoid this
QAbstractSpinBox *spinBox = nullptr;
switch ( numberDef->dataType() )
{
case QgsProcessingParameterNumber::Double:
mDoubleSpinBox = new QgsDoubleSpinBox();
mDoubleSpinBox->setExpressionsEnabled( true );
mDoubleSpinBox->setDecimals( 6 );
// guess reasonable step value for double spin boxes
if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) &&
!qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() + 1 ) )
{
const double singleStep = calculateStep( numberDef->minimum(), numberDef->maximum() );
mDoubleSpinBox->setSingleStep( singleStep );
}
spinBox = mDoubleSpinBox;
break;
case QgsProcessingParameterNumber::Integer:
mSpinBox = new QgsSpinBox();
mSpinBox->setExpressionsEnabled( true );
spinBox = mSpinBox;
break;
}
spinBox->setToolTip( parameterDefinition()->toolTip() );
double max = 999999999;
if ( !qgsDoubleNear( numberDef->maximum(), std::numeric_limits<double>::max() ) )
{
max = numberDef->maximum();
}
double min = -999999999;
if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) )
{
min = numberDef->minimum();
}
if ( mDoubleSpinBox )
{
mDoubleSpinBox->setMinimum( min );
mDoubleSpinBox->setMaximum( max );
}
else
{
mSpinBox->setMinimum( static_cast< int >( min ) );
mSpinBox->setMaximum( static_cast< int >( max ) );
}
if ( numberDef->flags() & QgsProcessingParameterDefinition::FlagOptional )
{
mAllowingNull = true;
if ( mDoubleSpinBox )
{
mDoubleSpinBox->setShowClearButton( true );
const double min = mDoubleSpinBox->minimum() - 1;
mDoubleSpinBox->setMinimum( min );
mDoubleSpinBox->setValue( min );
}
else
{
mSpinBox->setShowClearButton( true );
const int min = mSpinBox->minimum() - 1;
mSpinBox->setMinimum( min );
mSpinBox->setValue( min );
}
spinBox->setSpecialValueText( tr( "Not set" ) );
}
if ( numberDef->defaultValue().isValid() )
{
// if default value for parameter, we clear to that
bool ok = false;
if ( mDoubleSpinBox )
{
double defaultVal = numberDef->defaultValue().toDouble( &ok );
if ( ok )
mDoubleSpinBox->setClearValue( defaultVal );
}
else
{
int intVal = numberDef->defaultValue().toInt( &ok );
if ( ok )
mSpinBox->setClearValue( intVal );
}
}
else if ( !qgsDoubleNear( numberDef->minimum(), std::numeric_limits<double>::lowest() ) && !mAllowingNull )
{
// otherwise we clear to the minimum, if it's set
if ( mDoubleSpinBox )
mDoubleSpinBox->setClearValue( numberDef->minimum() );
else
mSpinBox->setClearValue( static_cast< int >( numberDef->minimum() ) );
}
else if ( !mAllowingNull )
{
// last resort, we clear to 0
if ( mDoubleSpinBox )
{
mDoubleSpinBox->setValue( 0 );
mDoubleSpinBox->setClearValue( 0 );
}
else
{
mSpinBox->setValue( 0 );
mSpinBox->setClearValue( 0 );
}
}
if ( mDoubleSpinBox )
connect( mDoubleSpinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
else if ( mSpinBox )
connect( mSpinBox, qgis::overload<int>::of( &QgsSpinBox::valueChanged ), this, [ = ] { emit widgetValueHasChanged( this ); } );
return spinBox;
};
}
return nullptr;
}
void QgsProcessingNumericWidgetWrapper::setWidgetValue( const QVariant &value, QgsProcessingContext &context )
{
if ( mDoubleSpinBox )
{
if ( mAllowingNull && !value.isValid() )
mDoubleSpinBox->clear();
else
{
const double v = QgsProcessingParameters::parameterAsDouble( parameterDefinition(), value, context );
mDoubleSpinBox->setValue( v );
}
}
else if ( mSpinBox )
{
if ( mAllowingNull && !value.isValid() )
mSpinBox->clear();
else
{
const int v = QgsProcessingParameters::parameterAsInt( parameterDefinition(), value, context );
mSpinBox->setValue( v );
}
}
}
QVariant QgsProcessingNumericWidgetWrapper::widgetValue() const
{
if ( mDoubleSpinBox )
{
if ( mAllowingNull && qgsDoubleNear( mDoubleSpinBox->value(), mDoubleSpinBox->minimum() ) )
return QVariant();
else
return mDoubleSpinBox->value();
}
else if ( mSpinBox )
{
if ( mAllowingNull && mSpinBox->value() == mSpinBox->minimum() )
return QVariant();
else
return mSpinBox->value();
}
else
return QVariant();
}
QStringList QgsProcessingNumericWidgetWrapper::compatibleParameterTypes() const
{
return QStringList()
<< QgsProcessingParameterString::typeName()
<< QgsProcessingParameterNumber::typeName()
<< QgsProcessingParameterDistance::typeName();
}
QStringList QgsProcessingNumericWidgetWrapper::compatibleOutputTypes() const
{
return QStringList() << QgsProcessingOutputNumber::typeName()
<< QgsProcessingOutputString::typeName();
}
QList<int> QgsProcessingNumericWidgetWrapper::compatibleDataTypes() const
{
return QList< int >();
}
double QgsProcessingNumericWidgetWrapper::calculateStep( const double minimum, const double maximum )
{
const double valueRange = maximum - minimum;
if ( valueRange <= 1.0 )
{
const double step = valueRange / 10.0;
// round to 1 significant figure
return qgsRound( step, std::floor( std::log( step ) ) );
}
else
{
return 1.0;
}
}
QString QgsProcessingNumericWidgetWrapper::parameterType() const
{
return QgsProcessingParameterNumber::typeName();
}
QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingNumericWidgetWrapper::createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type )
{
return new QgsProcessingNumericWidgetWrapper( parameter, type );
}
///@endcond PRIVATE

View File

@ -27,6 +27,9 @@ class QComboBox;
class QLineEdit;
class QPlainTextEdit;
class QgsProjectionSelectionWidget;
class QgsSpinBox;
class QgsDoubleSpinBox;
///@cond PRIVATE
@ -135,6 +138,48 @@ class GUI_EXPORT QgsProcessingStringWidgetWrapper : public QgsAbstractProcessing
friend class TestProcessingGui;
};
class GUI_EXPORT QgsProcessingNumericWidgetWrapper : public QgsAbstractProcessingParameterWidgetWrapper, public QgsProcessingParameterWidgetFactoryInterface
{
Q_OBJECT
public:
QgsProcessingNumericWidgetWrapper( const QgsProcessingParameterDefinition *parameter = nullptr,
QgsProcessingGui::WidgetType type = QgsProcessingGui::Standard, QWidget *parent = nullptr );
// QgsProcessingParameterWidgetFactoryInterface
QString parameterType() const override;
QgsAbstractProcessingParameterWidgetWrapper *createWidgetWrapper( const QgsProcessingParameterDefinition *parameter, QgsProcessingGui::WidgetType type ) override;
// QgsProcessingParameterWidgetWrapper interface
QWidget *createWidget() override SIP_FACTORY;
protected:
void setWidgetValue( const QVariant &value, QgsProcessingContext &context ) override;
QVariant widgetValue() const override;
QStringList compatibleParameterTypes() const override;
QStringList compatibleOutputTypes() const override;
QList< int > compatibleDataTypes() const override;
private:
static double calculateStep( double minimum, double maximum );
QgsSpinBox *mSpinBox = nullptr;
QgsDoubleSpinBox *mDoubleSpinBox = nullptr;
QLineEdit *mLineEdit = nullptr;
QPlainTextEdit *mPlainTextEdit = nullptr;
bool mAllowingNull = false;
friend class TestProcessingGui;
};
///@endcond PRIVATE