diff --git a/python/gui/qgsscalecombobox.sip b/python/gui/qgsscalecombobox.sip index ad7d1053157..973d8b8895e 100644 --- a/python/gui/qgsscalecombobox.sip +++ b/python/gui/qgsscalecombobox.sip @@ -17,9 +17,11 @@ class QgsScaleComboBox : QComboBox //! Function to set the selected scale from text bool setScaleString( const QString& scaleTxt ); //! Function to read the selected scale as double - double scale(); + double scale() const; //! Function to set the selected scale from double void setScale( double scale ); + //! Function to read the min scale + double minScale() const; //! Helper function to convert a double to scale string // Performs rounding, so an exact representation is not to @@ -30,10 +32,12 @@ class QgsScaleComboBox : QComboBox signals: //! Signal is emitted when *user* has finished editing/selecting a new scale. - void scaleChanged(); + void scaleChanged( double scale ); public slots: void updateScales( const QStringList &scales = QStringList() ); + //! Function to set the min scale + void setMinScale( double scale ); protected: void showPopup(); diff --git a/python/gui/qgsscalewidget.sip b/python/gui/qgsscalewidget.sip index a573238a81f..1256f135417 100644 --- a/python/gui/qgsscalewidget.sip +++ b/python/gui/qgsscalewidget.sip @@ -26,9 +26,11 @@ class QgsScaleWidget : QWidget //! Function to set the selected scale from text bool setScaleString( const QString& scaleTxt ); //! Function to read the selected scale as double - double scale(); + double scale() const; //! Function to set the selected scale from double void setScale( double scale ); + //! Function to read the min scale + double minScale() const; //! Helper function to convert a double to scale string // Performs rounding, so an exact representation is not to @@ -43,9 +45,12 @@ class QgsScaleWidget : QWidget //! assign the current scale from the map canvas void setScaleFromCanvas(); + //! Function to set the min scale + void setMinScale( double scale ); + signals: //! Signal is emitted when *user* has finished editing/selecting a new scale. - void scaleChanged(); + void scaleChanged( double scale ); }; diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 81a25056ec8..31fec1dbc32 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -2057,7 +2057,7 @@ void QgisApp::createStatusBar() mScaleEdit->setToolTip( tr( "Current map scale (formatted as x:y)" ) ); statusBar()->addPermanentWidget( mScaleEdit, 0 ); - connect( mScaleEdit, SIGNAL( scaleChanged() ), this, SLOT( userScale() ) ); + connect( mScaleEdit, SIGNAL( scaleChanged( double ) ), this, SLOT( userScale() ) ); if ( QgsMapCanvas::rotationEnabled() ) { diff --git a/src/gui/qgsscalecombobox.cpp b/src/gui/qgsscalecombobox.cpp index 6c51da57bf4..b40011b6ed0 100644 --- a/src/gui/qgsscalecombobox.cpp +++ b/src/gui/qgsscalecombobox.cpp @@ -24,7 +24,7 @@ #include #include -QgsScaleComboBox::QgsScaleComboBox( QWidget* parent ) : QComboBox( parent ), mScale( 1.0 ) +QgsScaleComboBox::QgsScaleComboBox( QWidget* parent ) : QComboBox( parent ), mScale( 1.0 ), mMinScale( 0.0 ) { updateScales(); @@ -126,6 +126,11 @@ bool QgsScaleComboBox::setScaleString( const QString& scaleTxt ) { bool ok; double newScale = toDouble( scaleTxt, &ok ); + double oldScale = mScale; + if ( newScale < mMinScale ) + { + newScale = mMinScale; + } if ( ! ok ) { return false; @@ -135,12 +140,16 @@ bool QgsScaleComboBox::setScaleString( const QString& scaleTxt ) mScale = newScale; setEditText( toString( mScale ) ); clearFocus(); + if ( mScale != oldScale ) + { + emit scaleChanged( mScale ); + } return true; } } //! Function to read the selected scale as double -double QgsScaleComboBox::scale() +double QgsScaleComboBox::scale() const { return mScale; } @@ -154,34 +163,24 @@ void QgsScaleComboBox::setScale( double scale ) //! Slot called when QComboBox has changed void QgsScaleComboBox::fixupScale() { - double newScale; - double oldScale = mScale; - bool ok, userSetScale; QStringList txtList = currentText().split( ':' ); - userSetScale = txtList.size() != 2; + bool userSetScale = txtList.size() != 2; - // QgsDebugMsg( QString( "entered with oldScale: %1" ).arg( oldScale ) ); - newScale = toDouble( currentText(), &ok ); + bool ok; + double newScale = toDouble( currentText(), &ok ); // Valid string representation - if ( ok && ( newScale != oldScale ) ) + if ( ok ) { // if a user types scale = 2345, we transform to 1:2345 if ( userSetScale && newScale >= 1.0 ) { - mScale = 1 / newScale; + newScale = 1 / newScale; } - else - { - mScale = newScale; - } - setScale( mScale ); - emit scaleChanged(); + setScale( newScale ); } else { - // Invalid string representation or same scale - // Reset to the old setScale( mScale ); } } @@ -241,4 +240,11 @@ double QgsScaleComboBox::toDouble( const QString& scaleString, bool * returnOk ) return scale; } - +void QgsScaleComboBox::setMinScale( double scale ) +{ + mMinScale = scale; + if ( mScale < scale ) + { + setScale( scale ); + } +} \ No newline at end of file diff --git a/src/gui/qgsscalecombobox.h b/src/gui/qgsscalecombobox.h index b5c10a234eb..2e0046ce71a 100644 --- a/src/gui/qgsscalecombobox.h +++ b/src/gui/qgsscalecombobox.h @@ -36,9 +36,11 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox //! Function to set the selected scale from text bool setScaleString( const QString& scaleTxt ); //! Function to read the selected scale as double - double scale(); + double scale() const; //! Function to set the selected scale from double void setScale( double scale ); + //! Function to read the min scale + double minScale() const { return mMinScale; } //! Helper function to convert a double to scale string // Performs rounding, so an exact representation is not to @@ -49,10 +51,12 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox signals: //! Signal is emitted when *user* has finished editing/selecting a new scale. - void scaleChanged(); + void scaleChanged( double scale ); public slots: void updateScales( const QStringList &scales = QStringList() ); + //! Function to set the min scale + void setMinScale( double scale ); protected: void showPopup() override; @@ -62,6 +66,7 @@ class GUI_EXPORT QgsScaleComboBox : public QComboBox private: double mScale; + double mMinScale; }; #endif // QGSSCALECOMBOBOX_H diff --git a/src/gui/qgsscalerangewidget.cpp b/src/gui/qgsscalerangewidget.cpp index 857c214df48..2c055cb8ab1 100644 --- a/src/gui/qgsscalerangewidget.cpp +++ b/src/gui/qgsscalerangewidget.cpp @@ -43,6 +43,7 @@ QgsScaleRangeWidget::QgsScaleRangeWidget( QWidget *parent ) mMinimumScaleWidget = new QgsScaleWidget( this ); mMaximumScaleWidget = new QgsScaleWidget( this ); + connect( mMinimumScaleWidget, SIGNAL( scaleChanged( double ) ), mMaximumScaleWidget, SLOT( setMinScale( double ) ) ); mMinimumScaleWidget->setShowCurrentScaleButton( true ); mMaximumScaleWidget->setShowCurrentScaleButton( true ); reloadProjectScales(); diff --git a/src/gui/qgsscalewidget.cpp b/src/gui/qgsscalewidget.cpp index de1f8fdbc73..8f350dd7a3c 100644 --- a/src/gui/qgsscalewidget.cpp +++ b/src/gui/qgsscalewidget.cpp @@ -37,7 +37,7 @@ QgsScaleWidget::QgsScaleWidget( QWidget *parent ) layout->addWidget( mCurrentScaleButton ); mCurrentScaleButton->hide(); - connect( mScaleComboBox, SIGNAL( scaleChanged() ), this, SIGNAL( scaleChanged() ) ); + connect( mScaleComboBox, SIGNAL( scaleChanged( double ) ), this, SIGNAL( scaleChanged( double ) ) ); connect( mCurrentScaleButton, SIGNAL( clicked() ), this, SLOT( setScaleFromCanvas() ) ); } diff --git a/src/gui/qgsscalewidget.h b/src/gui/qgsscalewidget.h index eb7249a27e0..f10c10d98f3 100644 --- a/src/gui/qgsscalewidget.h +++ b/src/gui/qgsscalewidget.h @@ -32,6 +32,8 @@ class GUI_EXPORT QgsScaleWidget : public QWidget { Q_OBJECT Q_PROPERTY( bool showCurrentScaleButton READ showCurrentScaleButton WRITE setShowCurrentScaleButton ) + Q_PROPERTY( bool scale READ scale WRITE setScale NOTIFY scaleChanged ) + Q_PROPERTY( bool minScale READ minScale WRITE setMinScale ) public: explicit QgsScaleWidget( QWidget *parent = nullptr ); @@ -51,9 +53,11 @@ class GUI_EXPORT QgsScaleWidget : public QWidget //! Function to set the selected scale from text bool setScaleString( const QString& scaleTxt ) { return mScaleComboBox->setScaleString( scaleTxt ); } //! Function to read the selected scale as double - double scale() { return mScaleComboBox->scale();} + double scale() const { return mScaleComboBox->scale();} //! Function to set the selected scale from double void setScale( double scale ) { return mScaleComboBox->setScale( scale ); } + //! Function to read the min scale + double minScale() const { return mScaleComboBox->minScale(); } //! Helper function to convert a double to scale string // Performs rounding, so an exact representation is not to @@ -68,9 +72,12 @@ class GUI_EXPORT QgsScaleWidget : public QWidget //! assign the current scale from the map canvas void setScaleFromCanvas(); + //! Function to set the min scale + void setMinScale( double scale ) { mScaleComboBox->setMinScale( scale ); } + signals: //! Signal is emitted when *user* has finished editing/selecting a new scale. - void scaleChanged(); + void scaleChanged( double scale ); private: QgsScaleComboBox* mScaleComboBox; diff --git a/src/gui/qgsunitselectionwidget.cpp b/src/gui/qgsunitselectionwidget.cpp index 2ab6b915c4e..f1720d813c8 100644 --- a/src/gui/qgsunitselectionwidget.cpp +++ b/src/gui/qgsunitselectionwidget.cpp @@ -28,8 +28,9 @@ QgsMapUnitScaleDialog::QgsMapUnitScaleDialog( QWidget* parent ) mSpinBoxMaxSize->setShowClearButton( false ); connect( mCheckBoxMinScale, SIGNAL( toggled( bool ) ), this, SLOT( configureMinComboBox() ) ); connect( mCheckBoxMaxScale, SIGNAL( toggled( bool ) ), this, SLOT( configureMaxComboBox() ) ); - connect( mComboBoxMinScale, SIGNAL( scaleChanged() ), this, SLOT( configureMaxComboBox() ) ); - connect( mComboBoxMaxScale, SIGNAL( scaleChanged() ), this, SLOT( configureMinComboBox() ) ); + connect( mComboBoxMinScale, SIGNAL( scaleChanged( double ) ), this, SLOT( configureMaxComboBox() ) ); + connect( mComboBoxMinScale, SIGNAL( scaleChanged( double ) ), mComboBoxMaxScale, SLOT( setMinScale( double ) ) ); + connect( mComboBoxMaxScale, SIGNAL( scaleChanged( double ) ), this, SLOT( configureMinComboBox() ) ); connect( mCheckBoxMinSize, SIGNAL( toggled( bool ) ), mSpinBoxMinSize, SLOT( setEnabled( bool ) ) ); connect( mCheckBoxMaxSize, SIGNAL( toggled( bool ) ), mSpinBoxMaxSize, SLOT( setEnabled( bool ) ) ); diff --git a/tests/src/gui/testqgsscalecombobox.cpp b/tests/src/gui/testqgsscalecombobox.cpp index a55e7c851c1..98d65e0ebfb 100644 --- a/tests/src/gui/testqgsscalecombobox.cpp +++ b/tests/src/gui/testqgsscalecombobox.cpp @@ -29,7 +29,7 @@ class TestQgsScaleComboBox : public QObject Q_OBJECT public: TestQgsScaleComboBox() - : s( 0 ) + : s( nullptr ) {} private slots: @@ -39,7 +39,10 @@ class TestQgsScaleComboBox : public QObject void cleanup();// will be called after every testfunction. void basic(); void slot_test(); + void min_test(); private: + void enterScale( const QString& scale ); + void enterScale( double scale ); QgsScaleComboBox *s; }; @@ -48,73 +51,56 @@ void TestQgsScaleComboBox::initTestCase() QgsApplication::init(); QgsApplication::initQgis(); - // Create a combobox, and init with predefined scales. - s = new QgsScaleComboBox(); - QgsDebugMsg( QString( "Initial scale is %1" ).arg( s->scaleString() ) ); } void TestQgsScaleComboBox::cleanupTestCase() { - delete s; QgsApplication::exitQgis(); } void TestQgsScaleComboBox::init() { + // Create a combobox, and init with predefined scales. + s = new QgsScaleComboBox(); + QgsDebugMsg( QString( "Initial scale is %1" ).arg( s->scaleString() ) ); } void TestQgsScaleComboBox::basic() { - QLineEdit *l = s->lineEdit(); - // Testing conversion from "1:nnn". - l->setText( "" ); - QTest::keyClicks( l, "1:2345" ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( "1:2345" ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( QLocale::system().toString( 2345 ) ) ); QCOMPARE( s->scale(), 1.0 / 2345.0 ); // Testing conversion from number to "1:x" - l->setText( "" ); - QTest::keyClicks( l, QLocale::system().toString( 0.02 ) ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( 0.02 ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( QLocale::system().toString( 50 ) ) ); QCOMPARE( s->scale(), 0.02 ); // Testing conversion from number to "1:x" - l->setText( "" ); - QTest::keyClicks( l, QLocale::system().toString( 42 ) ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( 42 ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( QLocale::system().toString( 42 ) ) ); QCOMPARE( s->scale(), 1.0 / 42.0 ); // Testing conversion from number to "1:x,000" - l->setText( "" ); QString str = QString( "1%01000%01000" ).arg( QLocale::system().groupSeparator() ); - QTest::keyClicks( l, str ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( str ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( str ) ); QCOMPARE( s->scale(), 1.0 / 1000000.0 ); // Testing conversion from number to "1:x,000" with wonky separators //(eg four digits between thousands, which should be fixed automatically) - l->setText( "" ); str = QString( "1%010000%01000" ).arg( QLocale::system().groupSeparator() ); QString fixedStr = QString( "10%01000%01000" ).arg( QLocale::system().groupSeparator() ); - QTest::keyClicks( l, str ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( str ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( fixedStr ) ); QCOMPARE( s->scale(), 1.0 / 10000000.0 ); // Testing rounding and conversion from illegal - l->setText( "" ); - QTest::keyClicks( l, QLocale::system().toString( 0.24 ) ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( 0.24 ); - l->setText( "" ); - QTest::keyClicks( l, "1:x:2" ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( "1:x:2" ); QCOMPARE( s->scaleString(), QString( "1:%1" ).arg( QLocale::system().toString( 4 ) ) ); QCOMPARE( s->scale(), 0.25 ); @@ -138,19 +124,48 @@ void TestQgsScaleComboBox::basic() void TestQgsScaleComboBox::slot_test() { QLineEdit *l = s->lineEdit(); - l->setText( "" ); - QSignalSpy spyScaleChanged( s, SIGNAL( scaleChanged() ) ); + QSignalSpy spyScaleChanged( s, SIGNAL( scaleChanged( double ) ) ); QSignalSpy spyFixup( l, SIGNAL( editingFinished() ) ); - QTest::keyClicks( l, QLocale::system().toString( 0.02 ) ); - QTest::keyClick( l, Qt::Key_Return ); + enterScale( 0.02 ); QCOMPARE( spyFixup.count(), 2 ); // Qt emits twice!? QCOMPARE( spyScaleChanged.count(), 1 ); } +void TestQgsScaleComboBox::min_test() +{ + s->setMinScale( 0.01 ); + + enterScale( 0.02 ); + QCOMPARE( s->scale(), 0.02 ); + + enterScale( 0.002 ); + QCOMPARE( s->scale(), 0.01 ); + + s->setMinScale( 0.015 ); + QCOMPARE( s->scale(), 0.015 ); + + s->setScale( 0.5 ); + QCOMPARE( s->scale(), 0.5 ); +} + +void TestQgsScaleComboBox::enterScale( const QString& scale ) +{ + QLineEdit *l = s->lineEdit(); + l->setText( "" ); + QTest::keyClicks( l, scale ); + QTest::keyClick( l, Qt::Key_Return ); +} + +void TestQgsScaleComboBox::enterScale( double scale ) +{ + enterScale( QLocale::system().toString( scale ) ); +} + void TestQgsScaleComboBox::cleanup() { + delete s; } QTEST_MAIN( TestQgsScaleComboBox )