1 /***************************************************************************
2     testqgsmapcanvas.cpp
3     ---------------------
4     begin                : December 2013
5     copyright            : (C) 2013 by Martin Dobias
6     email                : wonder dot sk at gmail dot com
7  ***************************************************************************
8  *                                                                         *
9  *   This program is free software; you can redistribute it and/or modify  *
10  *   it under the terms of the GNU General Public License as published by  *
11  *   the Free Software Foundation; either version 2 of the License, or     *
12  *   (at your option) any later version.                                   *
13  *                                                                         *
14  ***************************************************************************/
15 
16 #include "qgstest.h"
17 #include <QSignalSpy>
18 #include <QtMath>
19 
20 #include "qgsapplication.h"
21 #include "qgsmapcanvas.h"
22 #include "qgsvectorlayer.h"
23 #include "qgsproject.h"
24 #include "qgsrenderchecker.h"
25 #include "qgsvectordataprovider.h"
26 #include "qgsmaptoolpan.h"
27 #include "qgscustomdrophandler.h"
28 #include "qgsreferencedgeometry.h"
29 
30 namespace QTest
31 {
32   template<>
toString(const QgsRectangle & r)33   char *toString( const QgsRectangle &r )
34   {
35     QByteArray ba = r.toString().toLocal8Bit();
36     return qstrdup( ba.data() );
37   }
38 }
39 
40 class QgsMapToolTest : public QgsMapTool // clazy:exclude=missing-qobject-macro
41 {
42   public:
QgsMapToolTest(QgsMapCanvas * canvas)43     QgsMapToolTest( QgsMapCanvas *canvas ) : QgsMapTool( canvas ) {}
44 
canvasToolTipEvent(QHelpEvent * e)45     bool canvasToolTipEvent( QHelpEvent *e ) override
46     {
47       Q_UNUSED( e );
48       mGotTooltipEvent = true;
49       return true;
50     }
gotTooltipEvent() const51     bool gotTooltipEvent() const
52     {
53       return mGotTooltipEvent;
54     }
55 
56   private:
57     bool mGotTooltipEvent = false;
58 
59 };
60 
61 class TestQgsMapCanvas : public QObject
62 {
63     Q_OBJECT
64   public:
65     TestQgsMapCanvas() = default;
66 
67   private slots:
68     void initTestCase(); // will be called before the first testfunction is executed.
69     void cleanupTestCase(); // will be called after the last testfunction was executed.
70 
71     void testPanByKeyboard();
72     void testSetExtent();
73     void testMagnification();
74     void testMagnificationExtent();
75     void testMagnificationScale();
76     void testScaleLockCanvasResize();
77     void testZoomByWheel();
78     void testShiftZoom();
79     void testDragDrop();
80     void testZoomResolutions();
81     void testTooltipEvent();
82     void testMapLayers();
83 
84   private:
85     QgsMapCanvas *mCanvas = nullptr;
86 };
87 
88 
89 
initTestCase()90 void TestQgsMapCanvas::initTestCase()
91 {
92   QgsApplication::init(); // init paths for CRS lookup
93   QgsApplication::initQgis();
94 
95   mCanvas = new QgsMapCanvas();
96 }
97 
cleanupTestCase()98 void TestQgsMapCanvas::cleanupTestCase()
99 {
100   QgsApplication::exitQgis();
101 }
102 
103 
testPanByKeyboard()104 void TestQgsMapCanvas::testPanByKeyboard()
105 {
106   // The keys to simulate
107   const QList<Qt::Key> keys = QList<Qt::Key>() << Qt::Key_Left << Qt::Key_Down << Qt::Key_Right << Qt::Key_Up;
108 
109   // The canvas rotations to test
110   const QList<double> rotations = QList<double>() << 0.0 << 30.0;
111 
112   const QgsRectangle initialExtent( 100, 100, 110, 110 );
113 
114   for ( const double rotation : rotations )
115   {
116     // Set rotation and initial extent
117     mCanvas->setRotation( rotation );
118     mCanvas->setExtent( initialExtent );
119 
120     // Save actual extent, simulate panning by keyboard and verify the extent is unchanged
121     const QgsRectangle originalExtent = mCanvas->extent();
122     for ( const Qt::Key key : keys )
123     {
124       const QgsRectangle tempExtent = mCanvas->extent();
125       QKeyEvent keyEvent( QEvent::KeyPress, key, Qt::NoModifier );
126       QApplication::sendEvent( mCanvas, &keyEvent );
127       QVERIFY( mCanvas->extent() != tempExtent );
128     }
129     QVERIFY( mCanvas->extent() == originalExtent );
130   }
131 }
132 
testSetExtent()133 void TestQgsMapCanvas::testSetExtent()
134 {
135   mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) );
136   QVERIFY( mCanvas->setReferencedExtent( QgsReferencedRectangle( QgsRectangle( 0, 0, 10, 10 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:4326" ) ) ) ) );
137   QCOMPARE( mCanvas->extent().toString( 0 ), QStringLiteral( "-3,-3 : 13,13" ) );
138   QVERIFY( mCanvas->setReferencedExtent( QgsReferencedRectangle( QgsRectangle( 16259461, -2477192, 16391255, -2372535 ), QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3857" ) ) ) ) );
139   QCOMPARE( mCanvas->extent().toString( 0 ), QStringLiteral( "146,-22 : 147,-21" ) );
140   mCanvas->setDestinationCrs( QgsCoordinateReferenceSystem( ) );
141 }
142 
testMagnification()143 void TestQgsMapCanvas::testMagnification()
144 {
145   // test directory
146   const QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/';
147   QString controlImageDir = testDataDir + "control_images/expected_map_magnification/";
148 
149   // prepare spy and unit testing stuff
150   QgsRenderChecker checker;
151   checker.setControlPathPrefix( QStringLiteral( "mapcanvas" ) );
152   checker.setColorTolerance( 5 );
153 
154   QSignalSpy spy( mCanvas, SIGNAL( mapCanvasRefreshed() ) );
155 
156   QEventLoop loop;
157   QObject::connect( mCanvas, SIGNAL( mapCanvasRefreshed() ), &loop, SLOT( quit() ) );
158 
159   QTimer timer;
160   QObject::connect( &timer, SIGNAL( timeout() ), &loop, SLOT( quit() ) );
161 
162   QTemporaryFile tmpFile;
163   tmpFile.setAutoRemove( false );
164   tmpFile.open(); // fileName is not available until open
165   const QString tmpName = tmpFile.fileName();
166   tmpFile.close();
167 
168   // build vector layer
169   const QString myPointsFileName = testDataDir + "points.shp";
170   const QFileInfo myPointFileInfo( myPointsFileName );
171   QgsVectorLayer *layer = new QgsVectorLayer( myPointFileInfo.filePath(),
172       myPointFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
173 
174   // prepare map canvas
175   mCanvas->setLayers( QList<QgsMapLayer *>() << layer );
176   QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << layer );
177 
178   mCanvas->setExtent( layer->extent() );
179 
180   // refresh and wait for rendering
181   mCanvas->refresh();
182   timer.start( 3000 );
183   loop.exec();
184   QCOMPARE( spy.count(), 1 );
185   spy.clear();
186 
187   // control image with magnification factor 1.0
188   mCanvas->saveAsImage( tmpName );
189 
190   checker.setControlName( QStringLiteral( "expected_map_magnification" ) );
191   checker.setRenderedImage( tmpName );
192   checker.setSizeTolerance( 10, 10 );
193   QCOMPARE( checker.compareImages( "map_magnification", 100 ), true );
194 
195   // set magnification factor (auto refresh)
196   mCanvas->setMagnificationFactor( 6.5 );
197   QCOMPARE( mCanvas->magnificationFactor(), 6.5 );
198 
199   // wait for rendering
200   timer.start( 3000 );
201   loop.exec();
202   QCOMPARE( spy.count(), 1 );
203   spy.clear();
204 
205   // control image with magnification factor 6.5
206   mCanvas->saveAsImage( tmpName );
207 
208   checker.setRenderedImage( tmpName );
209   checker.setControlName( QStringLiteral( "expected_map_magnification_6_5" ) );
210   controlImageDir = testDataDir + "control_images/";
211   checker.setSizeTolerance( 10, 10 );
212   QCOMPARE( checker.compareImages( "map_magnification_6_5", 100 ), true );
213 
214   // set magnification factor (auto refresh)
215   mCanvas->setMagnificationFactor( 1.0 );
216   QCOMPARE( mCanvas->magnificationFactor(), 1.0 );
217 
218   // wait for rendering
219   timer.start( 3000 );
220   loop.exec();
221   QCOMPARE( spy.count(), 1 );
222   spy.clear();
223 
224   // control image with magnification factor 1.0
225   mCanvas->saveAsImage( tmpName );
226 
227   checker.setControlName( QStringLiteral( "expected_map_magnification" ) );
228   checker.setRenderedImage( tmpName );
229   checker.setSizeTolerance( 10, 10 );
230   QCOMPARE( checker.compareImages( QStringLiteral( "map_magnification" ), 100 ), true );
231 }
232 
compareExtent(const QgsRectangle & initialExtent,const QgsRectangle & extent)233 void compareExtent( const QgsRectangle &initialExtent,
234                     const QgsRectangle &extent )
235 {
236   QGSCOMPARENEAR( initialExtent.xMinimum(), extent.xMinimum(), 0.00000000001 );
237   QGSCOMPARENEAR( initialExtent.xMaximum(), extent.xMaximum(), 0.00000000001 );
238   QGSCOMPARENEAR( initialExtent.yMinimum(), extent.yMinimum(), 0.00000000001 );
239   QGSCOMPARENEAR( initialExtent.yMaximum(), extent.yMaximum(), 0.00000000001 );
240 }
241 
testMagnificationExtent()242 void TestQgsMapCanvas::testMagnificationExtent()
243 {
244   // build vector layer
245   const QString testDataDir = QStringLiteral( TEST_DATA_DIR ) + '/';
246   const QString myPointsFileName = testDataDir + "points.shp";
247   const QFileInfo myPointFileInfo( myPointsFileName );
248   QgsVectorLayer *layer = new QgsVectorLayer( myPointFileInfo.filePath(),
249       myPointFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
250 
251   // prepare map canvas
252   mCanvas->setLayers( QList<QgsMapLayer *>() << layer );
253   QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << layer );
254 
255   // zoomToFullExtent
256   mCanvas->zoomToFullExtent();
257   QgsRectangle initialExtent = mCanvas->extent();
258 
259   mCanvas->setMagnificationFactor( 4.0 );
260   mCanvas->setMagnificationFactor( 1.0 );
261 
262   compareExtent( mCanvas->extent(), initialExtent );
263 
264   // setExtent with layer extent
265   mCanvas->setExtent( layer->extent() );
266   initialExtent = mCanvas->extent();
267 
268   mCanvas->setMagnificationFactor( 4.0 );
269   mCanvas->setMagnificationFactor( 1.0 );
270 
271   compareExtent( mCanvas->extent(), initialExtent );
272 
273   // zoomToSelected
274   const QgsFeature f1( layer->dataProvider()->fields(), 1 );
275   const QgsFeature f2( layer->dataProvider()->fields(), 2 );
276   QgsFeatureIds ids;
277   ids << f1.id() << f2.id();
278   layer->selectByIds( ids );
279 
280   mCanvas->zoomToSelected( layer );
281   initialExtent = mCanvas->extent();
282 
283   mCanvas->setMagnificationFactor( 4.0 );
284   mCanvas->setMagnificationFactor( 1.0 );
285 
286   compareExtent( mCanvas->extent(), initialExtent );
287 
288   // zoomToFeatureIds
289   mCanvas->zoomToFeatureIds( layer, ids );
290   initialExtent = mCanvas->extent();
291 
292   mCanvas->setMagnificationFactor( 4.0 );
293   mCanvas->setMagnificationFactor( 1.0 );
294 
295   compareExtent( mCanvas->extent(), initialExtent );
296 
297   // zoomIn / zoomOut
298   initialExtent = mCanvas->extent();
299   mCanvas->zoomIn();
300 
301   mCanvas->setMagnificationFactor( 4.0 );
302   mCanvas->zoomIn();
303   mCanvas->zoomOut();
304   mCanvas->setMagnificationFactor( 1.0 );
305 
306   mCanvas->zoomOut();
307 
308   compareExtent( mCanvas->extent(), initialExtent );
309 
310   // zoomScale
311   initialExtent = mCanvas->extent();
312   const double scale = mCanvas->scale();
313   mCanvas->zoomScale( 6.052017 * 10e7 );
314 
315   mCanvas->setMagnificationFactor( 4.0 );
316   mCanvas->setMagnificationFactor( 1.0 );
317 
318   mCanvas->zoomScale( scale );
319   compareExtent( mCanvas->extent(), initialExtent );
320 }
321 
testMagnificationScale()322 void TestQgsMapCanvas::testMagnificationScale()
323 {
324   mCanvas->setMagnificationFactor( 1.0 );
325   const double initialScale = mCanvas->scale();
326 
327   mCanvas->setMagnificationFactor( 4.0 );
328   QCOMPARE( initialScale, mCanvas->scale() );
329 
330   mCanvas->setMagnificationFactor( 7.5 );
331   QCOMPARE( initialScale, mCanvas->scale() );
332 
333   mCanvas->setMagnificationFactor( 1.0 );
334   QCOMPARE( initialScale, mCanvas->scale() );
335 }
336 
testScaleLockCanvasResize()337 void TestQgsMapCanvas::testScaleLockCanvasResize()
338 {
339   const QSize prevSize = mCanvas->size();
340 
341   mCanvas->resize( 600, 400 );
342   QgsApplication::sendPostedEvents( mCanvas );
343   mCanvas->resizeEvent( nullptr );
344   QCOMPARE( mCanvas->width(), 600 );
345   QCOMPARE( mCanvas->height(), 400 );
346 
347   mCanvas->setMagnificationFactor( 2.0 );
348   const double initialScale = mCanvas->scale();
349   mCanvas->setScaleLocked( true );
350 
351   mCanvas->resize( 300, 200 );
352   QgsApplication::sendPostedEvents( mCanvas );
353   mCanvas->resizeEvent( nullptr );
354   QCOMPARE( mCanvas->width(), 300 );
355   QCOMPARE( mCanvas->height(), 200 );
356 
357   QCOMPARE( mCanvas->magnificationFactor(), 2.0 );
358   QCOMPARE( mCanvas->scale(), initialScale );
359 
360   mCanvas->setScaleLocked( false );
361   mCanvas->setMagnificationFactor( 1.0 );
362   mCanvas->resize( prevSize );
363   QgsApplication::sendPostedEvents( mCanvas );
364   mCanvas->resizeEvent( nullptr );
365 }
366 
testZoomByWheel()367 void TestQgsMapCanvas::testZoomByWheel()
368 {
369   mCanvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
370   const QgsRectangle initialExtent = mCanvas->extent();
371   const double originalWidth = initialExtent.width();
372   const double originalHeight = initialExtent.height();
373 
374   mCanvas->setWheelFactor( 2 );
375 
376   //test zoom out
377   QWheelEvent e( QPoint( 0, 0 ), -QWheelEvent::DefaultDeltasPerStep, Qt::NoButton, Qt::NoModifier );
378   mCanvas->wheelEvent( &e );
379   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth * 2.0, 0.1 );
380   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight * 2.0, 0.1 );
381 
382   //test zoom in
383   e = QWheelEvent( QPoint( 0, 0 ), QWheelEvent::DefaultDeltasPerStep, Qt::NoButton, Qt::NoModifier );
384   mCanvas->wheelEvent( &e );
385   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth, 0.1 );
386   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight, 0.1 );
387 
388   // test zoom out with ctrl
389   e = QWheelEvent( QPoint( 0, 0 ), -QWheelEvent::DefaultDeltasPerStep, Qt::NoButton, Qt::ControlModifier );
390   mCanvas->wheelEvent( &e );
391   QGSCOMPARENEAR( mCanvas->extent().width(), 1.05 * originalWidth, 0.1 );
392   QGSCOMPARENEAR( mCanvas->extent().height(), 1.05 * originalHeight, 0.1 );
393 
394   //test zoom in with ctrl
395   e = QWheelEvent( QPoint( 0, 0 ), QWheelEvent::DefaultDeltasPerStep, Qt::NoButton, Qt::ControlModifier );
396   mCanvas->wheelEvent( &e );
397   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth, 0.1 );
398   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight, 0.1 );
399 }
400 
testShiftZoom()401 void TestQgsMapCanvas::testShiftZoom()
402 {
403   mCanvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
404   const QgsRectangle initialExtent = mCanvas->extent();
405   const double originalWidth = initialExtent.width();
406   const double originalHeight = initialExtent.height();
407 
408   const QPoint startPos = QPoint( mCanvas->width() / 4, mCanvas->height() / 4 );
409   const QPoint endPos = QPoint( mCanvas->width() * 3 / 4.0, mCanvas->height() * 3 / 4.0 );
410 
411   QgsMapToolPan panTool( mCanvas );
412 
413   // start by testing a tool with shift-zoom enabled
414   mCanvas->setMapTool( &panTool );
415 
416   QMouseEvent e( QMouseEvent::MouseButtonPress, startPos,
417                  Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
418   mCanvas->mousePressEvent( &e );
419   e = QMouseEvent( QMouseEvent::MouseMove, endPos,
420                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
421   mCanvas->mouseMoveEvent( &e );
422   e = QMouseEvent( QMouseEvent::MouseButtonRelease, endPos,
423                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
424   mCanvas->mouseReleaseEvent( &e );
425 
426   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth / 2.0, 0.2 );
427   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight / 2.0, 0.2 );
428 
429   //reset
430   mCanvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
431 
432   //test that a shift-click (no movement) will not zoom
433   e = QMouseEvent( QMouseEvent::MouseButtonPress, startPos,
434                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
435   mCanvas->mousePressEvent( &e );
436   e = QMouseEvent( QMouseEvent::MouseMove, startPos,
437                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
438   mCanvas->mouseMoveEvent( &e );
439   e = QMouseEvent( QMouseEvent::MouseButtonRelease, startPos,
440                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
441   mCanvas->mouseReleaseEvent( &e );
442 
443   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth, 0.0001 );
444   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight, 0.0001 );
445 
446   //reset
447   mCanvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
448 
449   //test with map tool which does not have shift-zoom enabled
450   QgsMapToolTest mapTool( mCanvas );
451   mCanvas->setMapTool( &mapTool );
452 
453   e = QMouseEvent( QMouseEvent::MouseButtonPress, startPos,
454                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
455   mCanvas->mousePressEvent( &e );
456   e = QMouseEvent( QMouseEvent::MouseMove, endPos,
457                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
458   mCanvas->mouseMoveEvent( &e );
459   e = QMouseEvent( QMouseEvent::MouseButtonRelease, endPos,
460                    Qt::LeftButton, Qt::LeftButton, Qt::ShiftModifier );
461   mCanvas->mouseReleaseEvent( &e );
462 
463   QGSCOMPARENEAR( mCanvas->extent().width(), originalWidth, 0.00001 );
464   QGSCOMPARENEAR( mCanvas->extent().height(), originalHeight, 0.00001 );
465 }
466 
467 class TestNoDropHandler : public QgsCustomDropHandler
468 {
469     Q_OBJECT
470 
471   public:
472 
customUriProviderKey() const473     QString customUriProviderKey() const override { return QStringLiteral( "test" ); }
canHandleCustomUriCanvasDrop(const QgsMimeDataUtils::Uri &,QgsMapCanvas *)474     bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) override { return false; }
handleCustomUriCanvasDrop(const QgsMimeDataUtils::Uri &,QgsMapCanvas *) const475     bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) const override { return false; }
476 };
477 
478 class TestYesDropHandler : public QgsCustomDropHandler
479 {
480     Q_OBJECT
481 
482   public:
483 
customUriProviderKey() const484     QString customUriProviderKey() const override { return QStringLiteral( "test" ); }
canHandleCustomUriCanvasDrop(const QgsMimeDataUtils::Uri &,QgsMapCanvas *)485     bool canHandleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) override { return true; }
handleCustomUriCanvasDrop(const QgsMimeDataUtils::Uri &,QgsMapCanvas *) const486     bool handleCustomUriCanvasDrop( const QgsMimeDataUtils::Uri &, QgsMapCanvas * ) const override { return true; }
487 };
488 
testDragDrop()489 void TestQgsMapCanvas::testDragDrop()
490 {
491   // default drag, should not be accepted
492   std::unique_ptr< QMimeData > data = std::make_unique< QMimeData >();
493   std::unique_ptr< QDragEnterEvent > event = std::make_unique< QDragEnterEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
494   mCanvas->dragEnterEvent( event.get() );
495   QVERIFY( !event->isAccepted() );
496 
497   // with mime data
498   QgsMimeDataUtils::UriList list;
499   QgsMimeDataUtils::Uri uri;
500   uri.name = QStringLiteral( "name" );
501   uri.providerKey = QStringLiteral( "test" );
502   list << uri;
503   data.reset( QgsMimeDataUtils::encodeUriList( list ) );
504   event = std::make_unique< QDragEnterEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
505   mCanvas->dragEnterEvent( event.get() );
506   // still not accepted by default
507   QVERIFY( !event->isAccepted() );
508 
509   // add a custom drop handler to the canvas
510   TestNoDropHandler handler;
511   mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler );
512   mCanvas->dragEnterEvent( event.get() );
513   // not accepted by handler
514   QVERIFY( !event->isAccepted() );
515 
516   TestYesDropHandler handler2;
517   mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler << &handler2 );
518   mCanvas->dragEnterEvent( event.get() );
519   // IS accepted by handler
520   QVERIFY( event->isAccepted() );
521 
522   // check drop event logic
523   mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() );
524   std::unique_ptr< QDropEvent > dropEvent = std::make_unique< QDropEvent >( QPoint( 10, 10 ), Qt::CopyAction, data.get(), Qt::LeftButton, Qt::NoModifier );
525   mCanvas->dropEvent( dropEvent.get() );
526   QVERIFY( !dropEvent->isAccepted() );
527   mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler );
528   mCanvas->dropEvent( dropEvent.get() );
529   QVERIFY( !dropEvent->isAccepted() );
530   mCanvas->setCustomDropHandlers( QVector< QPointer< QgsCustomDropHandler > >() << &handler << &handler2 );
531   mCanvas->dropEvent( dropEvent.get() );
532   // is accepted!
533   QVERIFY( dropEvent->isAccepted() );
534 }
535 
testZoomResolutions()536 void TestQgsMapCanvas::testZoomResolutions()
537 {
538   mCanvas->setExtent( QgsRectangle( 0, 0, 10, 10 ) );
539   const double resolution = mCanvas->mapSettings().mapUnitsPerPixel();
540 
541   const double nextResolution = qCeil( resolution ) + 1;
542   QList<double> resolutions = QList<double>() << nextResolution << ( 2.5 * nextResolution ) << ( 3.6 * nextResolution ) << ( 4.7 * nextResolution );
543   mCanvas->setZoomResolutions( resolutions );
544 
545   mCanvas->zoomOut();
546   QGSCOMPARENEAR( mCanvas->mapSettings().mapUnitsPerPixel(), resolutions[0], 0.0001 );
547 
548   mCanvas->zoomOut();
549   QGSCOMPARENEAR( mCanvas->mapSettings().mapUnitsPerPixel(), resolutions[1], 0.0001 );
550 
551   mCanvas->zoomIn();
552   QGSCOMPARENEAR( mCanvas->mapSettings().mapUnitsPerPixel(), resolutions[0], 0.0001 );
553 
554   QCOMPARE( mCanvas->zoomResolutions(), resolutions );
555 }
556 
testTooltipEvent()557 void TestQgsMapCanvas::testTooltipEvent()
558 {
559   QgsMapToolTest mapTool( mCanvas );
560   mCanvas->setMapTool( &mapTool );
561 
562   QHelpEvent helpEvent( QEvent::ToolTip, QPoint( 10, 10 ), QPoint( 10, 10 ) );
563 
564   QApplication::sendEvent( mCanvas->viewport(), &helpEvent );
565 
566   QVERIFY( mapTool.gotTooltipEvent() );
567 }
568 
testMapLayers()569 void TestQgsMapCanvas::testMapLayers()
570 {
571   QgsProject::instance()->clear();
572   //set up canvas with a mix of project and non-project layers
573   QgsVectorLayer *vl1 = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=halig:string&field=valig:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) );
574   QVERIFY( vl1->isValid() );
575   QgsProject::instance()->addMapLayer( vl1 );
576 
577   std::unique_ptr< QgsVectorLayer > vl2 = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point?crs=epsg:3946&field=halig:string&field=valig:string" ), QStringLiteral( "vl2" ), QStringLiteral( "memory" ) );
578   QVERIFY( vl2->isValid() );
579 
580   std::unique_ptr< QgsMapCanvas > canvas = std::make_unique< QgsMapCanvas >();
581   canvas->setLayers( { vl1, vl2.get() } );
582 
583   QCOMPARE( canvas->layers(), QList< QgsMapLayer * >( { vl1, vl2.get() } ) );
584   // retrieving layer by id should work for both layers from the project AND for freestanding layers
585   QCOMPARE( canvas->layer( vl1->id() ), vl1 );
586   QCOMPARE( canvas->layer( vl2->id() ), vl2.get() );
587   QCOMPARE( canvas->layer( QStringLiteral( "xxx" ) ), nullptr );
588 }
589 
590 QGSTEST_MAIN( TestQgsMapCanvas )
591 #include "testqgsmapcanvas.moc"
592