diff --git a/python/core/qgsmapsettings.sip b/python/core/qgsmapsettings.sip index e139aaa6c2b..1292d05c303 100644 --- a/python/core/qgsmapsettings.sip +++ b/python/core/qgsmapsettings.sip @@ -17,7 +17,7 @@ class QgsMapSettings //! The actual visible extent used for rendering could be slightly different //! since the given extent may be expanded in order to fit the aspect ratio //! of output size. Use visibleExtent() to get the resulting extent. - void setExtent( const QgsRectangle& rect ); + void setExtent( const QgsRectangle& rect, bool magnified = true ); //! Return the size of the resulting map image QSize outputSize() const; @@ -39,6 +39,13 @@ class QgsMapSettings //! Set DPI used for conversion between real world units (e.g. mm) and pixels void setOutputDpi( int dpi ); + //! Set the magnification factor. + //! @note added in 2.16 + void setMagnificationFactor( double factor ); + //! Return the magnification factor. + //! @note added in 2.16 + double magnificationFactor() const; + //! Get list of layer IDs for map rendering //! The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top) QStringList layers() const; diff --git a/python/gui/qgsmapcanvas.sip b/python/gui/qgsmapcanvas.sip index 2de6e8e58f7..3982d17bd82 100644 --- a/python/gui/qgsmapcanvas.sip +++ b/python/gui/qgsmapcanvas.sip @@ -50,6 +50,16 @@ class QgsMapCanvas : QGraphicsView //! Destructor ~QgsMapCanvas(); + //! Sets the factor of magnification to apply to the map canvas. Indeed, we + //! increase/decrease the DPI of the map settings according to this factor + //! in order to render marker point, labels, ... bigger. + //! @note added in 2.16 + void setMagnificationFactor( double level ); + + //! Returns the magnification factor + //! @note added in 2.16 + double magnificationFactor() const; + void setLayerSet( QList& layers ); void setCurrentLayer( QgsMapLayer* layer ); diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index ae19651227d..5de99eab090 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -51,6 +51,7 @@ SET(QGIS_APP_SRCS qgsrulebasedlabelingwidget.cpp qgssavestyletodbdialog.cpp qgsstatusbarcoordinateswidget.cpp + qgsstatusbarmagnifierwidget.cpp qgsversioninfo.cpp qgswelcomepageitemsmodel.cpp qgswelcomepage.cpp @@ -229,6 +230,7 @@ SET (QGIS_APP_MOC_HDRS qgssavestyletodbdialog.h qgsshortcutsmanager.h qgsstatusbarcoordinateswidget.h + qgsstatusbarmagnifierwidget.h qgsversioninfo.h qgswelcomepageitemsmodel.h qgswelcomepage.h diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index c0c88745f62..cc2722ad50e 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -123,6 +123,7 @@ #include "qgscomposermanager.h" #include "qgscomposerview.h" #include "qgsstatusbarcoordinateswidget.h" +#include "qgsstatusbarmagnifierwidget.h" #include "qgsconfigureshortcutsdialog.h" #include "qgscoordinatetransform.h" #include "qgscoordinateutils.h" @@ -545,6 +546,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh , mScaleLabel( nullptr ) , mScaleEdit( nullptr ) , mScaleEditValidator( nullptr ) + , mMagnifierWidget( nullptr ) , mCoordsEdit( nullptr ) , mRotationLabel( nullptr ) , mRotationEdit( nullptr ) @@ -1001,6 +1003,7 @@ QgisApp::QgisApp() , mScaleLabel( nullptr ) , mScaleEdit( nullptr ) , mScaleEditValidator( nullptr ) + , mMagnifierWidget( nullptr ) , mCoordsEdit( nullptr ) , mRotationLabel( nullptr ) , mRotationEdit( nullptr ) @@ -2161,6 +2164,13 @@ void QgisApp::createStatusBar() statusBar()->addPermanentWidget( mScaleEdit, 0 ); connect( mScaleEdit, SIGNAL( scaleChanged( double ) ), this, SLOT( userScale() ) ); + // zoom widget + QSettings mySettings; + mMagnifierWidget = new QgsStatusBarMagnifierWidget( statusBar(), mMapCanvas ); + mMagnifierWidget->setFont( myFont ); + mMagnifierWidget->setMagnificationLevel( mySettings.value( "/qgis/magnifier_level", 100 ).toInt() ); + statusBar()->addPermanentWidget( mMagnifierWidget, 0 ); + if ( QgsMapCanvas::rotationEnabled() ) { // add a widget to show/set current rotation @@ -8602,6 +8612,8 @@ void QgisApp::showOptionsDialog( QWidget *parent, const QString& currentPage ) layer->setLayerName( layer->originalName() ); } + mMagnifierWidget->setMagnificationLevel( mySettings.value( "/qgis/magnifier_level" ).toInt() ); + //update any open compositions so they reflect new composer settings //we have to push the changes to the compositions here, because compositions //have no access to qgisapp and accordingly can't listen in to changes diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 3b816795e77..eb7aa47bd5b 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -45,6 +45,7 @@ class QgsComposer; class QgsComposerManager; class QgsComposerView; class QgsStatusBarCoordinatesWidget; +class QgsStatusBarMagnifierWidget; class QgsContrastEnhancement; class QgsCustomLayerOrderWidget; class QgsDoubleSpinBox; @@ -1595,6 +1596,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow //! The validator for the mScaleEdit QValidator * mScaleEditValidator; + //! zoom widget + QgsStatusBarMagnifierWidget *mMagnifierWidget; + //! Widget that will live in the statusbar to display and edit coords QgsStatusBarCoordinatesWidget *mCoordsEdit; diff --git a/src/app/qgsoptions.cpp b/src/app/qgsoptions.cpp index 4d403be6f96..c4fb9c5b474 100644 --- a/src/app/qgsoptions.cpp +++ b/src/app/qgsoptions.cpp @@ -589,6 +589,13 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl ) mSimplifyMaximumScaleComboBox->updateScales( myScalesList ); mSimplifyMaximumScaleComboBox->setScale( 1.0 / mSettings->value( "/qgis/simplifyMaxScale", 1 ).toFloat() ); + // Magnifier + doubleSpinBoxMagnifierDefault->setRange( 100, 1000 ); + doubleSpinBoxMagnifierDefault->setSingleStep( 50 ); + doubleSpinBoxMagnifierDefault->setDecimals( 0 ); + doubleSpinBoxMagnifierDefault->setSuffix( "%" ); + doubleSpinBoxMagnifierDefault->setValue( mSettings->value( "/qgis/magnifier_level", 100 ).toInt() ); + // Slightly awkard here at the settings value is true to use QImage, // but the checkbox is true to use QPixmap chkAddedVisibility->setChecked( mSettings->value( "/qgis/new_layers_visible", true ).toBool() ); @@ -1192,6 +1199,9 @@ void QgsOptions::saveOptions() mSettings->setValue( "/qgis/simplifyLocal", !mSimplifyDrawingAtProvider->isChecked() ); mSettings->setValue( "/qgis/simplifyMaxScale", 1.0 / mSimplifyMaximumScaleComboBox->scale() ); + // magnification + mSettings->setValue( "/qgis/magnifier_level", doubleSpinBoxMagnifierDefault->value() ); + // project mSettings->setValue( "/qgis/projOpenAtLaunch", mProjectOnLaunchCmbBx->currentIndex() ); mSettings->setValue( "/qgis/projOpenAtLaunchPath", mProjectOnLaunchLineEdit->text() ); diff --git a/src/app/qgsstatusbarmagnifierwidget.cpp b/src/app/qgsstatusbarmagnifierwidget.cpp new file mode 100644 index 00000000000..9829e39ee4c --- /dev/null +++ b/src/app/qgsstatusbarmagnifierwidget.cpp @@ -0,0 +1,105 @@ +/*************************************************************************** + qgsstatusbarmagnifierwidget.cpp + begin : April 2016 + copyright : (C) 2016 Paul Blottiere, Oslandia + email : paul dot blottiere at oslandia dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include +#include +#include + +#include +#include "qgsstatusbarmagnifierwidget.h" +#include "qgsmapcanvas.h" +#include "qgsdoublespinbox.h" + +QgsStatusBarMagnifierWidget::QgsStatusBarMagnifierWidget( QWidget* parent, + QgsMapCanvas *canvas ) : + QWidget( parent ), + mCanvas( canvas ), + mMagnifier( 100 ), + mMagnifierMin( 100 ), + mMagnifierMax( 1000 ) +{ + // label + mLabel = new QLabel( this ); + mLabel->setMinimumWidth( 10 ); + mLabel->setMargin( 3 ); + mLabel->setAlignment( Qt::AlignCenter ); + mLabel->setFrameStyle( QFrame::NoFrame ); + mLabel->setText( tr( "Magnifier" ) ); + mLabel->setToolTip( tr( "Magnifier" ) ); + + mSpinBox = new QgsDoubleSpinBox( this ); + mSpinBox->setSuffix( "%" ); + mSpinBox->setClearValue( mMagnifierMin ); + mSpinBox->setKeyboardTracking( false ); + mSpinBox->setMaximumWidth( 120 ); + mSpinBox->setDecimals( 0 ); + mSpinBox->setRange( mMagnifierMin, mMagnifierMax ); + mSpinBox->setWrapping( false ); + mSpinBox->setSingleStep( 50 ); + mSpinBox->setToolTip( tr( "Magnifier level" ) ); + + connect( mSpinBox, SIGNAL( valueChanged( double ) ), this, + SLOT( updateMagnifier() ) ); + + // layout + mLayout = new QHBoxLayout( this ); + mLayout->addWidget( mLabel ); + mLayout->addWidget( mSpinBox ); + mLayout->setContentsMargins( 0, 0, 0, 0 ); + mLayout->setAlignment( Qt::AlignRight ); + mLayout->setSpacing( 0 ); + + setLayout( mLayout ); + + updateMagnifier(); +} + +QgsStatusBarMagnifierWidget::~QgsStatusBarMagnifierWidget() +{ +} + +double QgsStatusBarMagnifierWidget::magnificationLevel() +{ + return mMagnifier; +} + +void QgsStatusBarMagnifierWidget::setFont( const QFont& myFont ) +{ + mLabel->setFont( myFont ); + mSpinBox->setFont( myFont ); +} + +bool QgsStatusBarMagnifierWidget::setMagnificationLevel( int level ) +{ + bool rc = false; + + if ( level >= mMagnifierMin && level <= mMagnifierMax ) + { + mSpinBox->setValue( level ); + rc = true; + } + + return rc; +} + +void QgsStatusBarMagnifierWidget::updateMagnifier() +{ + // get current data + mMagnifier = mSpinBox->value(); + + // update map canvas + mCanvas->setMagnificationFactor( mMagnifier / double( mMagnifierMin ) ); +} diff --git a/src/app/qgsstatusbarmagnifierwidget.h b/src/app/qgsstatusbarmagnifierwidget.h new file mode 100644 index 00000000000..a49514d4671 --- /dev/null +++ b/src/app/qgsstatusbarmagnifierwidget.h @@ -0,0 +1,78 @@ +/*************************************************************************** + qgsstatusbarmagnifierwidget.h + begin : April 2016 + copyright : (C) 2016 Paul Blottiere, Oslandia + email : paul dot blottiere at oslandia dot com + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSSTATUSBARMAGNIFIERWIDGET_H +#define QGSSTATUSBARMAGNIFIERWIDGET_H + +class QLabel; +class QFont; +class QHBoxLayout; +class QgsMapCanvas; +class QgsDoubleSpinBox; + +#include + +/** + * A widget which lets the user select the current level of magnification to + * apply to the canvas. + * @note added in 2.16 + */ +class APP_EXPORT QgsStatusBarMagnifierWidget : public QWidget +{ + Q_OBJECT + + public: + + /** Constructor + * @param parent is the parent widget + * @param canvas the map canvas + */ + QgsStatusBarMagnifierWidget( QWidget* parent, QgsMapCanvas *canvas ); + + /** Destructor */ + virtual ~QgsStatusBarMagnifierWidget(); + + /** Set the font of the text + * @param font the font to use + */ + void setFont( const QFont& font ); + + /** Returns the current magnification level + * @return magnification level + */ + double magnificationLevel(); + + /** Set the magnification level + * @param level the magnification level + * @return true if the level is valid, false otherwise + */ + bool setMagnificationLevel( int level ); + + private slots: + + void updateMagnifier(); + + private: + QgsMapCanvas *mCanvas; + QHBoxLayout *mLayout; + QLabel *mLabel; + QgsDoubleSpinBox *mSpinBox; + int mMagnifier; + int mMagnifierMin; + int mMagnifierMax; +}; + +#endif diff --git a/src/core/qgsmapsettings.cpp b/src/core/qgsmapsettings.cpp index ab1a5e97bf0..19ce3ee4ea9 100644 --- a/src/core/qgsmapsettings.cpp +++ b/src/core/qgsmapsettings.cpp @@ -35,6 +35,7 @@ QgsMapSettings::QgsMapSettings() , mSize( QSize( 0, 0 ) ) , mExtent() , mRotation( 0.0 ) + , mMagnificationFactor( 1.0 ) , mProjectionsEnabled( false ) , mDestCRS( GEOCRS_ID, QgsCoordinateReferenceSystem::InternalCrsId ) // WGS 84 , mDatumTransformStore( mDestCRS ) @@ -53,15 +54,42 @@ QgsMapSettings::QgsMapSettings() setMapUnits( QGis::Degrees ); } +void QgsMapSettings::setMagnificationFactor( double factor ) +{ + double ratio = mMagnificationFactor / factor; + mMagnificationFactor = factor; + + double rot = rotation(); + setRotation( 0.0 ); + + QgsRectangle ext = visibleExtent(); + ext.scale( ratio ); + + mRotation = rot; + mExtent = ext; + mDpi = outputDpi() / ratio; + + updateDerived(); +} + +double QgsMapSettings::magnificationFactor() const +{ + return mMagnificationFactor; +} QgsRectangle QgsMapSettings::extent() const { return mExtent; } -void QgsMapSettings::setExtent( const QgsRectangle& extent ) +void QgsMapSettings::setExtent( const QgsRectangle& extent, bool magnified ) { - mExtent = extent; + QgsRectangle magnifiedExtent = extent; + + if ( !magnified ) + magnifiedExtent.scale( 1 / mMagnificationFactor ); + + mExtent = magnifiedExtent; updateDerived(); } diff --git a/src/core/qgsmapsettings.h b/src/core/qgsmapsettings.h index 1a80b5e449a..442e03fbb70 100644 --- a/src/core/qgsmapsettings.h +++ b/src/core/qgsmapsettings.h @@ -64,7 +64,7 @@ class CORE_EXPORT QgsMapSettings //! The actual visible extent used for rendering could be slightly different //! since the given extent may be expanded in order to fit the aspect ratio //! of output size. Use visibleExtent() to get the resulting extent. - void setExtent( const QgsRectangle& rect ); + void setExtent( const QgsRectangle& rect, bool magnified = true ); //! Return the size of the resulting map image QSize outputSize() const; @@ -86,6 +86,13 @@ class CORE_EXPORT QgsMapSettings //! Set DPI used for conversion between real world units (e.g. mm) and pixels void setOutputDpi( int dpi ); + //! Set the magnification factor. + //! @note added in 2.16 + void setMagnificationFactor( double factor ); + //! Return the magnification factor. + //! @note added in 2.16 + double magnificationFactor() const; + //! Get list of layer IDs for map rendering //! The layers are stored in the reverse order of how they are rendered (layer with index 0 will be on top) QStringList layers() const; @@ -261,6 +268,7 @@ class CORE_EXPORT QgsMapSettings QgsRectangle mExtent; double mRotation; + double mMagnificationFactor; QStringList mLayers; QMap mLayerStyleOverrides; @@ -283,7 +291,6 @@ class CORE_EXPORT QgsMapSettings double mMapUnitsPerPixel; double mScale; - // utiity stuff QgsScaleCalculator mScaleCalculator; QgsMapToPixel mMapToPixel; diff --git a/src/gui/editorwidgets/qgsdoublespinbox.h b/src/gui/editorwidgets/qgsdoublespinbox.h index d50e9fa8840..8934a78c785 100644 --- a/src/gui/editorwidgets/qgsdoublespinbox.h +++ b/src/gui/editorwidgets/qgsdoublespinbox.h @@ -80,10 +80,11 @@ class GUI_EXPORT QgsDoubleSpinBox : public QDoubleSpinBox virtual double valueFromText( const QString & text ) const override; virtual QValidator::State validate( QString & input, int & pos ) const override; + void paintEvent( QPaintEvent* e ) override; + protected: virtual void resizeEvent( QResizeEvent* event ) override; virtual void changeEvent( QEvent* event ) override; - virtual void paintEvent( QPaintEvent* event ) override; private slots: void changed( double value ); @@ -92,6 +93,8 @@ class GUI_EXPORT QgsDoubleSpinBox : public QDoubleSpinBox int frameWidth() const; bool shouldShowClearForValue( const double value ) const; + void updateStyleSheet( const QColor& backgroundColor = QColor() ); + bool mShowClearButton; ClearValueMode mClearValueMode; double mCustomClearValue; diff --git a/src/gui/qgsmapcanvas.cpp b/src/gui/qgsmapcanvas.cpp index c7d4211fd89..293628f3084 100644 --- a/src/gui/qgsmapcanvas.cpp +++ b/src/gui/qgsmapcanvas.cpp @@ -189,6 +189,7 @@ void QgsMapCanvasRendererSync::onLayersC2R() QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name ) : QGraphicsView( parent ) , mCanvasProperties( new CanvasProperties ) + , mMagnificationFactor( 1.0 ) , mJob( nullptr ) , mJobCancelled( false ) , mLabelingResults( nullptr ) @@ -310,6 +311,17 @@ QgsMapCanvas::~QgsMapCanvas() } // dtor +void QgsMapCanvas::setMagnificationFactor( double level ) +{ + mSettings.setMagnificationFactor( level ); + refresh(); +} + +double QgsMapCanvas::magnificationFactor() const +{ + return mSettings.magnificationFactor(); +} + void QgsMapCanvas::enableAntiAliasing( bool theFlag ) { mSettings.setFlag( QgsMapSettings::Antialiasing, theFlag ); @@ -757,7 +769,7 @@ void QgsMapCanvas::rendererJobFinished() p.end(); - mMap->setContent( img, imageRect( img, mJob->mapSettings() ) ); + mMap->setContent( img, imageRect( img, mSettings ) ); } // now we are in a slot called from mJob - do not delete it immediately @@ -782,7 +794,7 @@ QgsRectangle QgsMapCanvas::imageRect( const QImage& img, const QgsMapSettings& m void QgsMapCanvas::mapUpdateTimeout() { const QImage& img = mJob->renderedImage(); - mMap->setContent( img, imageRect( img, mJob->mapSettings() ) ); + mMap->setContent( img, imageRect( img, mSettings ) ); } void QgsMapCanvas::stopRendering() @@ -896,11 +908,11 @@ QgsRectangle QgsMapCanvas::fullExtent() const } // extent -void QgsMapCanvas::setExtent( QgsRectangle const & r ) +void QgsMapCanvas::setExtent( QgsRectangle const & r, bool magnified ) { QgsRectangle current = extent(); - if ( r == current ) + if (( r == current ) && magnified ) return; if ( r.isEmpty() ) @@ -918,7 +930,7 @@ void QgsMapCanvas::setExtent( QgsRectangle const & r ) } else { - mSettings.setExtent( r ); + mSettings.setExtent( r, magnified ); } emit extentsChanged(); updateScale(); @@ -959,7 +971,8 @@ void QgsMapCanvas::setCenter( const QgsPoint& center ) QgsRectangle( x - r.width() / 2.0, y - r.height() / 2.0, x + r.width() / 2.0, y + r.height() / 2.0 - ) + ), + true ); } // setCenter @@ -1527,7 +1540,7 @@ void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn ) QgsPoint center = getCoordinateTransform()->toMapPoint( x, y ); QgsRectangle r = mapSettings().visibleExtent(); r.scale( scaleFactor, ¢er ); - setExtent( r ); + setExtent( r, true ); refresh(); } @@ -2007,7 +2020,7 @@ void QgsMapCanvas::zoomByFactor( double scaleFactor, const QgsPoint* center ) { QgsRectangle r = mapSettings().extent(); r.scale( scaleFactor, center ); - setExtent( r ); + setExtent( r, true ); refresh(); } diff --git a/src/gui/qgsmapcanvas.h b/src/gui/qgsmapcanvas.h index 25785bdcc55..52506a93672 100644 --- a/src/gui/qgsmapcanvas.h +++ b/src/gui/qgsmapcanvas.h @@ -119,6 +119,16 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView //! Destructor ~QgsMapCanvas(); + //! Sets the factor of magnification to apply to the map canvas. Indeed, we + //! increase/decrease the DPI of the map settings according to this factor + //! in order to render marker point, labels, ... bigger. + //! @note added in 2.16 + void setMagnificationFactor( double level ); + + //! Returns the magnification factor + //! @note added in 2.16 + double magnificationFactor() const; + void setLayerSet( QList& layers ); void setCurrentLayer( QgsMapLayer* layer ); @@ -207,7 +217,7 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView QgsRectangle fullExtent() const; //! Set the extent of the map canvas - void setExtent( const QgsRectangle &r ); + void setExtent( const QgsRectangle &r, bool magnified = false ); //! Get the current map canvas rotation in clockwise degrees //! @note added in 2.8 @@ -722,6 +732,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView //! Timer that periodically fires while map rendering is in progress to update the visible map QTimer mMapUpdateTimer; + //! magnification factor + double mMagnificationFactor; + //! Job that takes care of map rendering in background QgsMapRendererQImageJob* mJob; diff --git a/src/ui/qgsoptionsbase.ui b/src/ui/qgsoptionsbase.ui index da24937642d..02c11477e22 100644 --- a/src/ui/qgsoptionsbase.ui +++ b/src/ui/qgsoptionsbase.ui @@ -2045,6 +2045,39 @@ + + + + 0 + + + + + Magnification level + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 20 + + + + + + diff --git a/tests/src/gui/testqgsmapcanvas.cpp b/tests/src/gui/testqgsmapcanvas.cpp index 5bb883cff15..b6709eb48fd 100644 --- a/tests/src/gui/testqgsmapcanvas.cpp +++ b/tests/src/gui/testqgsmapcanvas.cpp @@ -17,7 +17,11 @@ #include #include +#include #include +#include +#include +#include namespace QTest { @@ -43,6 +47,9 @@ class TestQgsMapCanvas : public QObject void testMapRendererInteraction(); void testPanByKeyboard(); + void testMagnification(); + void testMagnificationExtent(); + void testMagnificationScale(); private: QgsMapCanvas* mCanvas; @@ -53,6 +60,7 @@ class TestQgsMapCanvas : public QObject void TestQgsMapCanvas::initTestCase() { QgsApplication::init(); // init paths for CRS lookup + QgsApplication::initQgis(); mCanvas = new QgsMapCanvas(); } @@ -154,6 +162,203 @@ void TestQgsMapCanvas::testPanByKeyboard() } } +void TestQgsMapCanvas::testMagnification() +{ + // test directory + QString testDataDir = QString( TEST_DATA_DIR ) + '/'; + QString controlImageDir = testDataDir + "control_images/expected_map_magnification/"; + + // prepare spy and unit testing stuff + QgsRenderChecker checker; + checker.setControlPathPrefix( "mapcanvas" ); + checker.setColorTolerance( 5 ); + + QSignalSpy spy( mCanvas, SIGNAL( mapCanvasRefreshed() ) ); + + QEventLoop loop; + QObject::connect( mCanvas, SIGNAL( mapCanvasRefreshed() ), &loop, SLOT( quit() ) ); + + QTimer timer; + QObject::connect( &timer, SIGNAL( timeout() ), &loop, SLOT( quit() ) ); + + QTemporaryFile tmpFile; + tmpFile.setAutoRemove( false ); + tmpFile.open(); // fileName is not available until open + QString tmpName = tmpFile.fileName(); + tmpFile.close(); + + // build vector layer + QString myPointsFileName = testDataDir + "points.shp"; + QFileInfo myPointFileInfo( myPointsFileName ); + QgsVectorLayer *layer = new QgsVectorLayer( myPointFileInfo.filePath(), + myPointFileInfo.completeBaseName(), "ogr" ); + + // prepare map canvas + QList layers; + layers.append( layer ); + mCanvas->setLayerSet( layers ); + QgsMapLayerRegistry::instance()->addMapLayers( QList() << layer ); + + mCanvas->setExtent( layer->extent() ); + + // refresh and wait for rendering + mCanvas->refresh(); + timer.start( 3000 ); + loop.exec(); + QCOMPARE( spy.count(), 1 ); + spy.clear(); + + // control image with magnification factor 1.0 + mCanvas->saveAsImage( tmpName ); + + checker.setControlName( "expected_map_magnification" ); + checker.setRenderedImage( tmpName ); + checker.setSizeTolerance( 2, 2 ); + QCOMPARE( checker.compareImages( "map_magnification", 100 ), true ); + + // set magnification factor (auto refresh) + mCanvas->setMagnificationFactor( 6.5 ); + QCOMPARE( mCanvas->magnificationFactor(), 6.5 ); + + // wait for rendering + timer.start( 3000 ); + loop.exec(); + QCOMPARE( spy.count(), 1 ); + spy.clear(); + + // control image with magnification factor 6.5 + mCanvas->saveAsImage( tmpName ); + + checker.setRenderedImage( tmpName ); + checker.setControlName( "expected_map_magnification_6_5" ); + controlImageDir = testDataDir + "control_images/"; + checker.setSizeTolerance( 2, 2 ); + QCOMPARE( checker.compareImages( "map_magnification_6_5", 100 ), true ); + + // set magnification factor (auto refresh) + mCanvas->setMagnificationFactor( 1.0 ); + QCOMPARE( mCanvas->magnificationFactor(), 1.0 ); + + // wait for rendering + timer.start( 3000 ); + loop.exec(); + QCOMPARE( spy.count(), 1 ); + spy.clear(); + + // control image with magnification factor 1.0 + mCanvas->saveAsImage( tmpName ); + + checker.setControlName( "expected_map_magnification" ); + checker.setRenderedImage( tmpName ); + checker.setSizeTolerance( 2, 2 ); + QCOMPARE( checker.compareImages( "map_magnification", 100 ), true ); +} + +void compareExtent( const QgsRectangle &initialExtent, + const QgsRectangle &extent ) +{ + QVERIFY( qgsDoubleNear( initialExtent.xMinimum(), extent.xMinimum(), 0.00000000001 ) ); + QVERIFY( qgsDoubleNear( initialExtent.xMaximum(), extent.xMaximum(), 0.00000000001 ) ); + QVERIFY( qgsDoubleNear( initialExtent.yMinimum(), extent.yMinimum(), 0.00000000001 ) ); + QVERIFY( qgsDoubleNear( initialExtent.yMaximum(), extent.yMaximum(), 0.00000000001 ) ); +} + +void TestQgsMapCanvas::testMagnificationExtent() +{ + // build vector layer + QString testDataDir = QString( TEST_DATA_DIR ) + '/'; + QString myPointsFileName = testDataDir + "points.shp"; + QFileInfo myPointFileInfo( myPointsFileName ); + QgsVectorLayer *layer = new QgsVectorLayer( myPointFileInfo.filePath(), + myPointFileInfo.completeBaseName(), "ogr" ); + + // prepare map canvas + QList layers; + layers.append( layer ); + mCanvas->setLayerSet( layers ); + QgsMapLayerRegistry::instance()->addMapLayers( QList() << layer ); + + // zoomToFullExtent + mCanvas->zoomToFullExtent(); + QgsRectangle initialExtent = mCanvas->extent(); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->setMagnificationFactor( 1.0 ); + + compareExtent( mCanvas->extent(), initialExtent ); + + // setExtent with layer extent + mCanvas->setExtent( layer->extent() ); + initialExtent = mCanvas->extent(); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->setMagnificationFactor( 1.0 ); + + compareExtent( mCanvas->extent(), initialExtent ); + + // zoomToSelected + QgsFeature f1( layer->dataProvider()->fields(), 1 ); + QgsFeature f2( layer->dataProvider()->fields(), 2 ); + QgsFeatureIds ids; + ids << f1.id() << f2.id(); + layer->setSelectedFeatures( ids ); + + mCanvas->zoomToSelected( layer ); + initialExtent = mCanvas->extent(); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->setMagnificationFactor( 1.0 ); + + compareExtent( mCanvas->extent(), initialExtent ); + + // zoomToFeatureIds + mCanvas->zoomToFeatureIds( layer, ids ); + initialExtent = mCanvas->extent(); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->setMagnificationFactor( 1.0 ); + + compareExtent( mCanvas->extent(), initialExtent ); + + // zoomIn / zoomOut + initialExtent = mCanvas->extent(); + mCanvas->zoomIn(); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->zoomIn(); + mCanvas->zoomOut(); + mCanvas->setMagnificationFactor( 1.0 ); + + mCanvas->zoomOut(); + + compareExtent( mCanvas->extent(), initialExtent ); + + // zoomScale + initialExtent = mCanvas->extent(); + double scale = mCanvas->scale(); + mCanvas->zoomScale( 6.052017*10e7 ); + + mCanvas->setMagnificationFactor( 4.0 ); + mCanvas->setMagnificationFactor( 1.0 ); + + mCanvas->zoomScale( scale ); + compareExtent( mCanvas->extent(), initialExtent ); +} + +void TestQgsMapCanvas::testMagnificationScale() +{ + mCanvas->setMagnificationFactor( 1.0 ); + double initialScale = mCanvas->scale(); + + mCanvas->setMagnificationFactor( 4.0 ); + QCOMPARE( initialScale, mCanvas->scale() ); + + mCanvas->setMagnificationFactor( 7.5 ); + QCOMPARE( initialScale, mCanvas->scale() ); + + mCanvas->setMagnificationFactor( 1.0 ); + QCOMPARE( initialScale, mCanvas->scale() ); +} QTEST_MAIN( TestQgsMapCanvas ) #include "testqgsmapcanvas.moc" diff --git a/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification.png b/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification.png new file mode 100644 index 00000000000..adc621b68b8 Binary files /dev/null and b/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification.png differ diff --git a/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification_mask.png b/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification_mask.png new file mode 100644 index 00000000000..4ac975ff6c7 Binary files /dev/null and b/tests/testdata/control_images/mapcanvas/expected_map_magnification/expected_map_magnification_mask.png differ diff --git a/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5.png b/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5.png new file mode 100644 index 00000000000..12d0ad4712c Binary files /dev/null and b/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5.png differ diff --git a/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5_mask.png b/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5_mask.png new file mode 100644 index 00000000000..3816b4e4f42 Binary files /dev/null and b/tests/testdata/control_images/mapcanvas/expected_map_magnification_6_5/expected_map_magnification_6_5_mask.png differ