Skip to content
Permalink
Browse files

Add API to allow null values in QgsScaleComboBox

  • Loading branch information
nyalldawson committed Mar 13, 2019
1 parent cf1f06e commit 7c582063c15246a6e0d0a3b04212af072c55233b
@@ -46,6 +46,17 @@ Returns the selected scale as a double.
The scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.

.. seealso:: :py:func:`setScale`
%End

bool isNull() const;
%Docstring
Returns true if the combo box is currently set to a "null" value.

.. seealso:: :py:func:`setAllowNull`

.. seealso:: :py:func:`clear`

.. versionadded:: 3.8
%End

double minScale() const;
@@ -73,6 +84,32 @@ The returned value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map
If specified, ``ok`` will be set to ``True`` if the string was successfully interpreted as a scale.

.. seealso:: :py:func:`toString`
%End

void setAllowNull( bool allowNull );
%Docstring
Sets whether the scale combobox can be set to a NULL value.

.. seealso:: :py:func:`allowNull`

.. seealso:: :py:func:`isNull`

.. seealso:: :py:func:`clear`

.. versionadded:: 3.8
%End

bool allowNull() const;
%Docstring
Returns ``True`` if the combobox can be set to a NULL value.

.. seealso:: :py:func:`setAllowNull`

.. seealso:: :py:func:`isNull`

.. seealso:: :py:func:`clear`

.. versionadded:: 3.8
%End

signals:
@@ -105,6 +142,19 @@ Set the minimum allowed ``scale``. Set to 0 to disable the minimum scale.
The ``scale`` value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
Any scale lower than the minimum scale will automatically be converted to the minimum scale.
Except for 0 which is always allowed.
%End

void clear();
%Docstring
Sets the combo box to the null value.

This only has an effect if allowNull() is true.

.. seealso:: :py:func:`allowNull`

.. seealso:: :py:func:`isNull`

.. versionadded:: 3.8
%End

protected:
@@ -119,9 +119,21 @@ QString QgsScaleComboBox::scaleString() const

bool QgsScaleComboBox::setScaleString( const QString &string )
{
double oldScale = mScale;
if ( mAllowNull && string.trimmed().isEmpty() )
{
mScale = std::numeric_limits< double >::quiet_NaN();
setEditText( toString( mScale ) );
clearFocus();
if ( !std::isnan( oldScale ) )
{
emit scaleChanged( mScale );
}
return true;
}

bool ok;
double newScale = toDouble( string, &ok );
double oldScale = mScale;
if ( newScale > mMinScale && newScale != 0 && mMinScale != 0 )
{
newScale = mMinScale;
@@ -148,13 +160,24 @@ double QgsScaleComboBox::scale() const
return mScale;
}

bool QgsScaleComboBox::isNull() const
{
return std::isnan( mScale );
}

void QgsScaleComboBox::setScale( double scale )
{
setScaleString( toString( scale ) );
}

void QgsScaleComboBox::fixupScale()
{
if ( mAllowNull && currentText().trimmed().isEmpty() )
{
setScale( std::numeric_limits< double >::quiet_NaN() );
return;
}

QStringList txtList = currentText().split( ':' );
bool userSetScale = txtList.size() != 2;

@@ -179,6 +202,10 @@ void QgsScaleComboBox::fixupScale()

QString QgsScaleComboBox::toString( double scale )
{
if ( std::isnan( scale ) )
{
return QString();
}
if ( scale == 0 )
{
return QStringLiteral( "0" );
@@ -233,6 +260,18 @@ double QgsScaleComboBox::toDouble( const QString &scaleString, bool *returnOk )
return scale;
}

void QgsScaleComboBox::setAllowNull( bool allowNull )
{
mAllowNull = allowNull;
lineEdit()->setClearButtonEnabled( allowNull );
updateScales();
}

bool QgsScaleComboBox::allowNull() const
{
return mAllowNull;
}

void QgsScaleComboBox::setMinScale( double scale )
{
mMinScale = scale;
@@ -241,3 +280,9 @@ void QgsScaleComboBox::setMinScale( double scale )
setScale( mMinScale );
}
}

void QgsScaleComboBox::clear()
{
if ( allowNull() )
setScale( std::numeric_limits< double >::quiet_NaN() );
}
@@ -59,6 +59,15 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox
*/
double scale() const;

/**
* Returns true if the combo box is currently set to a "null" value.
*
* \see setAllowNull()
* \see clear()
* \since QGIS 3.8
*/
bool isNull() const;

/**
* Returns the minimum scale, or 0 if no minimum scale set.
* The \a scale value indicates the scale denominator, e.g. 1000.0 for a 1:1000 map.
@@ -84,6 +93,24 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox
*/
static double toDouble( const QString &string, bool *ok = nullptr );

/**
* Sets whether the scale combobox can be set to a NULL value.
* \see allowNull()
* \see isNull()
* \see clear()
* \since QGIS 3.8
*/
void setAllowNull( bool allowNull );

/**
* Returns TRUE if the combobox can be set to a NULL value.
* \see setAllowNull()
* \see isNull()
* \see clear()
* \since QGIS 3.8
*/
bool allowNull() const;

signals:

/**
@@ -115,6 +142,17 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox
*/
void setMinScale( double scale );

/**
* Sets the combo box to the null value.
*
* This only has an effect if allowNull() is true.
*
* \see allowNull()
* \see isNull()
* \since QGIS 3.8
*/
void clear();

protected:
void showPopup() override;

@@ -124,6 +162,7 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox
private:
double mScale = 1.0;
double mMinScale = 0.0;
bool mAllowNull = false;
};

#endif // QGSSCALECOMBOBOX_H
@@ -40,6 +40,7 @@ class TestQgsScaleComboBox : public QObject
void min_test();
void toString();
void toDouble();
void allowNull();

private:
void enterScale( const QString &scale );
@@ -157,6 +158,7 @@ void TestQgsScaleComboBox::toString()
QCOMPARE( QgsScaleComboBox::toString( 100.02134234 ), QStringLiteral( "1:100" ) );
QCOMPARE( QgsScaleComboBox::toString( 1 ), QStringLiteral( "1:1" ) );
QCOMPARE( QgsScaleComboBox::toString( 1.0 / 100 ), QStringLiteral( "100:1" ) );
QCOMPARE( QgsScaleComboBox::toString( std::numeric_limits< double >::quiet_NaN() ), QString() );
}

void TestQgsScaleComboBox::toDouble()
@@ -186,6 +188,56 @@ void TestQgsScaleComboBox::toDouble()
QVERIFY( !ok );
}

void TestQgsScaleComboBox::allowNull()
{
s->setScale( 50 );
QVERIFY( !s->allowNull() );
s->clear(); // no effect
QCOMPARE( s->scale(), 50.0 );
QVERIFY( !s->isNull() );

QSignalSpy spyScaleChanged( s, &QgsScaleComboBox::scaleChanged );
s->setAllowNull( true );
QVERIFY( s->allowNull() );

QVERIFY( s->lineEdit()->isClearButtonEnabled() );

s->setScaleString( QString() );
QCOMPARE( spyScaleChanged.count(), 1 );
QVERIFY( std::isnan( s->scale() ) );
QVERIFY( s->isNull() );
s->setScaleString( QStringLiteral( " " ) );
QVERIFY( std::isnan( s->scale() ) );
QVERIFY( s->lineEdit()->text().isEmpty() );
QCOMPARE( spyScaleChanged.count(), 1 );
QVERIFY( s->isNull() );

enterScale( 0.02 );
QCOMPARE( s->scale(), 50.0 );
QCOMPARE( spyScaleChanged.count(), 2 );
QCOMPARE( s->lineEdit()->text(), QStringLiteral( "1:50" ) );
QVERIFY( !s->isNull() );

enterScale( QString() );
QVERIFY( std::isnan( s->scale() ) );
QCOMPARE( spyScaleChanged.count(), 3 );
QVERIFY( s->lineEdit()->text().isEmpty() );
QVERIFY( s->isNull() );

enterScale( 0.02 );
QCOMPARE( s->scale(), 50.0 );
QCOMPARE( spyScaleChanged.count(), 4 );
s->clear();
QVERIFY( std::isnan( s->scale() ) );
QCOMPARE( spyScaleChanged.count(), 5 );
QVERIFY( s->lineEdit()->text().isEmpty() );
QVERIFY( s->isNull() );

s->setAllowNull( false );
QVERIFY( !s->allowNull() );
QVERIFY( !s->lineEdit()->isClearButtonEnabled() );
}

void TestQgsScaleComboBox::enterScale( const QString &scale )
{
QLineEdit *l = s->lineEdit();

0 comments on commit 7c58206

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