Skip to content

Commit

Permalink
Distance parameter unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Sep 21, 2018
1 parent 1166768 commit 33eb295
Show file tree
Hide file tree
Showing 3 changed files with 216 additions and 35 deletions.
87 changes: 53 additions & 34 deletions src/gui/processing/qgsprocessingwidgetwrapperimpl.cpp
Expand Up @@ -659,47 +659,65 @@ QgsAbstractProcessingParameterWidgetWrapper *QgsProcessingDistanceWidgetWrapper:
QWidget *QgsProcessingDistanceWidgetWrapper::createWidget()
{
QWidget *spin = QgsProcessingNumericWidgetWrapper::createWidget();
switch ( type() )
{
case QgsProcessingGui::Standard:
{
mLabel = new QLabel();
mUnitsCombo = new QComboBox();

mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceMeters ), QgsUnitTypes::DistanceMeters );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceKilometers ), QgsUnitTypes::DistanceKilometers );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceFeet ), QgsUnitTypes::DistanceFeet );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceMiles ), QgsUnitTypes::DistanceMiles );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceYards ), QgsUnitTypes::DistanceYards );

const int labelMargin = static_cast< int >( std::round( mUnitsCombo->fontMetrics().width( 'X' ) ) );
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget( spin, 1 );
layout->insertSpacing( 1, labelMargin / 2 );
layout->insertWidget( 2, mLabel );
layout->insertWidget( 3, mUnitsCombo );

// bit of fiddlyness here -- we want the initial spacing to only be visible
// when the warning label is shown, so it's embedded inside mWarningLabel
// instead of outside it
mWarningLabel = new QWidget();
QHBoxLayout *warningLayout = new QHBoxLayout();
warningLayout->setMargin( 0 );
warningLayout->setContentsMargins( 0, 0, 0, 0 );
QLabel *warning = new QLabel();
QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
const int size = static_cast< int >( std::max( 24.0, spin->minimumSize().height() * 0.5 ) );
warning->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
warning->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
warningLayout->insertSpacing( 0, labelMargin / 2 );
warningLayout->insertWidget( 1, warning );
mWarningLabel->setLayout( warningLayout );
layout->insertWidget( 4, mWarningLabel );

setUnits( QgsUnitTypes::DistanceUnknownUnit );

mLabel = new QLabel();
mUnitsCombo = new QComboBox();

mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceMeters ), QgsUnitTypes::DistanceMeters );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceKilometers ), QgsUnitTypes::DistanceKilometers );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceFeet ), QgsUnitTypes::DistanceFeet );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceMiles ), QgsUnitTypes::DistanceMiles );
mUnitsCombo->addItem( QgsUnitTypes::toString( QgsUnitTypes::DistanceYards ), QgsUnitTypes::DistanceYards );

const double labelMargin = mUnitsCombo->fontMetrics().width( 'X' );
QHBoxLayout *layout = new QHBoxLayout();
layout->addWidget( spin, 1 );
layout->insertSpacing( 1, labelMargin / 2 );
layout->insertWidget( 2, mLabel );
layout->insertWidget( 3, mUnitsCombo );
layout->insertSpacing( 4, labelMargin / 2 );

mWarningLabel = new QLabel();
QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "mIconWarning.svg" ) );
const int size = static_cast< int >( std::max( 24.0, spin->height() * 0.5 ) );
mWarningLabel->setPixmap( icon.pixmap( icon.actualSize( QSize( size, size ) ) ) );
mWarningLabel->setToolTip( tr( "Distance is in geographic degrees. Consider reprojecting to a projected local coordinate system for accurate results." ) );
layout->insertWidget( 4, mWarningLabel );
layout->insertSpacing( 5, labelMargin );
QWidget *w = new QWidget();
layout->setMargin( 0 );
layout->setContentsMargins( 0, 0, 0, 0 );
w->setLayout( layout );
return w;
}

setUnits( QgsUnitTypes::DistanceUnknownUnit );
case QgsProcessingGui::Batch:
case QgsProcessingGui::Modeler:
return spin;

QWidget *w = new QWidget();
layout->setMargin( 0 );
layout->setContentsMargins( 0, 0, 0, 0 );
w->setLayout( layout );
return w;
}
return nullptr;
}

void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstractProcessingParameterWidgetWrapper *> &wrappers )
{
QgsProcessingNumericWidgetWrapper::postInitialize( wrappers );
switch ( type() )
{
case QgsProcessingGui::Batch:
case QgsProcessingGui::Standard:
{
for ( const QgsAbstractProcessingParameterWidgetWrapper *wrapper : wrappers )
Expand All @@ -717,6 +735,7 @@ void QgsProcessingDistanceWidgetWrapper::postInitialize( const QList<QgsAbstract
break;
}

case QgsProcessingGui::Batch:
case QgsProcessingGui::Modeler:
break;
}
Expand Down Expand Up @@ -760,15 +779,15 @@ void QgsProcessingDistanceWidgetWrapper::setUnits( const QgsUnitTypes::DistanceU
mUnitsCombo->setCurrentIndex( mUnitsCombo->findData( units ) );
mUnitsCombo->show();
mLabel->hide();
mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
mBaseUnit = units;
}
mWarningLabel->setVisible( units == QgsUnitTypes::DistanceDegrees );
mBaseUnit = units;
}

QVariant QgsProcessingDistanceWidgetWrapper::widgetValue() const
{
const QVariant val = QgsProcessingNumericWidgetWrapper::widgetValue();
if ( val.type() == QVariant::Double && mUnitsCombo->isVisible() )
if ( val.type() == QVariant::Double && mUnitsCombo && mUnitsCombo->isVisible() )
{
QgsUnitTypes::DistanceUnit displayUnit = static_cast<QgsUnitTypes::DistanceUnit >( mUnitsCombo->currentData().toInt() );
return val.toDouble() * QgsUnitTypes::fromUnitToUnitFactor( displayUnit, mBaseUnit );
Expand Down
2 changes: 1 addition & 1 deletion src/gui/processing/qgsprocessingwidgetwrapperimpl.h
Expand Up @@ -209,7 +209,7 @@ class GUI_EXPORT QgsProcessingDistanceWidgetWrapper : public QgsProcessingNumeri

QgsUnitTypes::DistanceUnit mBaseUnit = QgsUnitTypes::DistanceUnknownUnit;
QLabel *mLabel = nullptr;
QLabel *mWarningLabel = nullptr;
QWidget *mWarningLabel = nullptr;
QComboBox *mUnitsCombo = nullptr;

friend class TestProcessingGui;
Expand Down
162 changes: 162 additions & 0 deletions tests/src/gui/testprocessinggui.cpp
Expand Up @@ -147,6 +147,7 @@ class TestProcessingGui : public QObject
void testCrsWrapper();
void testNumericWrapperDouble();
void testNumericWrapperInt();
void testDistanceWrapper();
};

void TestProcessingGui::initTestCase()
Expand Down Expand Up @@ -1149,5 +1150,166 @@ void TestProcessingGui::testNumericWrapperInt()
testWrapper( QgsProcessingGui::Modeler );
}

void TestProcessingGui::testDistanceWrapper()
{
QgsProcessingParameterDistance param( QStringLiteral( "distance" ), QStringLiteral( "distance" ) );

// standard wrapper
QgsProcessingDistanceWidgetWrapper wrapper( &param );

QgsProcessingContext context;
QWidget *w = wrapper.createWrappedWidget( context );

QSignalSpy spy( &wrapper, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
wrapper.setWidgetValue( 55.5, context );
QCOMPARE( spy.count(), 1 );
QCOMPARE( wrapper.widgetValue().toDouble(), 55.5 );
QCOMPARE( wrapper.mDoubleSpinBox->value(), 55.5 );
wrapper.setWidgetValue( -34.0, context );
QCOMPARE( spy.count(), 2 );
QCOMPARE( wrapper.widgetValue().toDouble(), -34.0 );
QCOMPARE( wrapper.mDoubleSpinBox->value(), -34.0 );

QLabel *l = wrapper.createWrappedLabel();
QVERIFY( l );
QCOMPARE( l->text(), QStringLiteral( "distance" ) );
QCOMPARE( l->toolTip(), param.toolTip() );
delete l;

// check signal
wrapper.mDoubleSpinBox->setValue( 43.0 );
QCOMPARE( spy.count(), 3 );

// test unit handling
w->show();

// crs values
wrapper.setUnitParameterValue( QStringLiteral( "EPSG:3111" ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
QVERIFY( !wrapper.mWarningLabel->isVisible() );
QVERIFY( wrapper.mUnitsCombo->isVisible() );
QVERIFY( !wrapper.mLabel->isVisible() );
QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );

wrapper.setUnitParameterValue( QStringLiteral( "EPSG:4326" ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
QVERIFY( wrapper.mWarningLabel->isVisible() );
QVERIFY( !wrapper.mUnitsCombo->isVisible() );
QVERIFY( wrapper.mLabel->isVisible() );

wrapper.setUnitParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3111" ) ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
QVERIFY( !wrapper.mWarningLabel->isVisible() );
QVERIFY( wrapper.mUnitsCombo->isVisible() );
QVERIFY( !wrapper.mLabel->isVisible() );
QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );

wrapper.setUnitParameterValue( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
QVERIFY( wrapper.mWarningLabel->isVisible() );
QVERIFY( !wrapper.mUnitsCombo->isVisible() );
QVERIFY( wrapper.mLabel->isVisible() );

// layer values
std::unique_ptr< QgsVectorLayer > vl = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "Polygon?crs=epsg:3111&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
wrapper.setUnitParameterValue( QVariant::fromValue( vl.get() ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
QVERIFY( !wrapper.mWarningLabel->isVisible() );
QVERIFY( wrapper.mUnitsCombo->isVisible() );
QVERIFY( !wrapper.mLabel->isVisible() );
QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );

std::unique_ptr< QgsVectorLayer > vl2 = qgis::make_unique< QgsVectorLayer >( QStringLiteral( "Polygon?crs=epsg:4326&field=pk:int" ), QStringLiteral( "vl" ), QStringLiteral( "memory" ) );
wrapper.setUnitParameterValue( QVariant::fromValue( vl2.get() ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "degrees" ) );
QVERIFY( wrapper.mWarningLabel->isVisible() );
QVERIFY( !wrapper.mUnitsCombo->isVisible() );
QVERIFY( wrapper.mLabel->isVisible() );

// unresolvable values
wrapper.setUnitParameterValue( QStringLiteral( "blah" ) );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "<unknown>" ) );
QVERIFY( !wrapper.mWarningLabel->isVisible() );
QVERIFY( !wrapper.mUnitsCombo->isVisible() );
QVERIFY( wrapper.mLabel->isVisible() );

// resolvable text value
const QString id = vl->id();
QgsProject::instance()->addMapLayer( vl.release() );
context.setProject( QgsProject::instance() );

TestProcessingContextGenerator generator( context );
wrapper.registerProcessingContextGenerator( &generator );
wrapper.setUnitParameterValue( id );
QCOMPARE( wrapper.mLabel->text(), QStringLiteral( "meters" ) );
QVERIFY( !wrapper.mWarningLabel->isVisible() );
QVERIFY( wrapper.mUnitsCombo->isVisible() );
QVERIFY( !wrapper.mLabel->isVisible() );
QCOMPARE( wrapper.mUnitsCombo->currentData().toInt(), static_cast< int >( QgsUnitTypes::DistanceMeters ) );

// using unit choice
wrapper.setParameterValue( 5, context );
QCOMPARE( wrapper.parameterValue().toDouble(), 5.0 );
wrapper.mUnitsCombo->setCurrentIndex( wrapper.mUnitsCombo->findData( QgsUnitTypes::DistanceKilometers ) );
QCOMPARE( wrapper.parameterValue().toDouble(), 5000.0 );
wrapper.setParameterValue( 2, context );
QCOMPARE( wrapper.parameterValue().toDouble(), 2000.0 );

wrapper.setUnitParameterValue( id );
QCOMPARE( wrapper.parameterValue().toDouble(), 2 );
wrapper.setParameterValue( 5, context );
QCOMPARE( wrapper.parameterValue().toDouble(), 5.0 );

delete w;

// batch wrapper
QgsProcessingDistanceWidgetWrapper wrapperB( &param, QgsProcessingGui::Batch );

w = wrapperB.createWrappedWidget( context );
QSignalSpy spy2( &wrapperB, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
wrapperB.setWidgetValue( 34, context );
QCOMPARE( spy2.count(), 1 );
QCOMPARE( wrapperB.widgetValue().toDouble(), 34.0 );
QCOMPARE( wrapperB.mDoubleSpinBox->value(), 34.0 );
wrapperB.setWidgetValue( -57, context );
QCOMPARE( spy2.count(), 2 );
QCOMPARE( wrapperB.widgetValue().toDouble(), -57.0 );
QCOMPARE( wrapperB.mDoubleSpinBox->value(), -57.0 );

// check signal
static_cast< QgsDoubleSpinBox * >( w )->setValue( 29 );
QCOMPARE( spy2.count(), 3 );

// should be no label in batch mode
QVERIFY( !wrapperB.createWrappedLabel() );
delete w;

// modeler wrapper
QgsProcessingDistanceWidgetWrapper wrapperM( &param, QgsProcessingGui::Modeler );

w = wrapperM.createWrappedWidget( context );
QSignalSpy spy3( &wrapperM, &QgsProcessingDistanceWidgetWrapper::widgetValueHasChanged );
wrapperM.setWidgetValue( 29, context );
QCOMPARE( wrapperM.widgetValue().toDouble(), 29 );
QCOMPARE( spy3.count(), 1 );
QCOMPARE( wrapperM.mDoubleSpinBox->value(), 29 );
wrapperM.setWidgetValue( -29, context );
QCOMPARE( wrapperM.widgetValue().toDouble(), -29 );
QCOMPARE( spy3.count(), 2 );
QCOMPARE( wrapperM.mDoubleSpinBox->value(), -29 );

// check signal
wrapperM.mDoubleSpinBox->setValue( 33 );
QCOMPARE( spy3.count(), 3 );

// should be a label in modeler mode
l = wrapperM.createWrappedLabel();
QVERIFY( l );
QCOMPARE( l->text(), QStringLiteral( "distance" ) );
QCOMPARE( l->toolTip(), param.toolTip() );
delete w;
delete l;
}

QGSTEST_MAIN( TestProcessingGui )
#include "testprocessinggui.moc"

0 comments on commit 33eb295

Please sign in to comment.