QGIS API Documentation  2.99.0-Master (585a4d3)
qgsmapcanvas.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 qgsmapcanvas.cpp - description
3 ------------------ -
4 begin : Sun Jun 30 2002
5 copyright : (C) 2002 by Gary E.Sherman
6 email : sherman at mrcc.com
7 ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 
19 #include <QtGlobal>
20 #include <QApplication>
21 #include <QCursor>
22 #include <QDir>
23 #include <QFile>
24 #include <QGraphicsItem>
25 #include <QGraphicsScene>
26 #include <QGraphicsView>
27 #include <QKeyEvent>
28 #include <QMouseEvent>
29 #include <QPainter>
30 #include <QPaintEvent>
31 #include <QPixmap>
32 #include <QRect>
33 #include <QTextStream>
34 #include <QResizeEvent>
35 #include <QString>
36 #include <QStringList>
37 #include <QWheelEvent>
38 
39 #include "qgis.h"
40 #include "qgssettings.h"
42 #include "qgsapplication.h"
43 #include "qgsexception.h"
45 #include "qgsfeatureiterator.h"
46 #include "qgslogger.h"
47 #include "qgsmapcanvas.h"
48 #include "qgsmapcanvasmap.h"
50 #include "qgsmaplayer.h"
51 #include "qgsmaptoolpan.h"
52 #include "qgsmaptoolzoom.h"
53 #include "qgsmaptopixel.h"
54 #include "qgsmapoverviewcanvas.h"
55 #include "qgsmaprenderercache.h"
59 #include "qgsmapsettingsutils.h"
60 #include "qgsmessagelog.h"
61 #include "qgsmessageviewer.h"
62 #include "qgspallabeling.h"
63 #include "qgsproject.h"
64 #include "qgsrubberband.h"
65 #include "qgsvectorlayer.h"
66 #include "qgsmapthemecollection.h"
68 #include <cmath>
69 
75 //TODO QGIS 3.0 - remove
77 {
78  public:
79 
83  CanvasProperties() = default;
84 
86  bool mouseButtonDown{ false };
87 
89  QPoint mouseLastXY;
90 
93 
95  bool panSelectorDown{ false };
96 };
97 
98 
99 
100 QgsMapCanvas::QgsMapCanvas( QWidget *parent )
101  : QGraphicsView( parent )
103  , mExpressionContextScope( tr( "Map Canvas" ) )
104 {
105  mScene = new QGraphicsScene();
106  setScene( mScene );
107  setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
108  setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
109  setMouseTracking( true );
110  setFocusPolicy( Qt::StrongFocus );
111 
112  mResizeTimer = new QTimer( this );
113  mResizeTimer->setSingleShot( true );
114  connect( mResizeTimer, &QTimer::timeout, this, &QgsMapCanvas::refresh );
115 
116  mRefreshTimer = new QTimer( this );
117  mRefreshTimer->setSingleShot( true );
118  connect( mRefreshTimer, &QTimer::timeout, this, &QgsMapCanvas::refreshMap );
119 
120  // create map canvas item which will show the map
121  mMap = new QgsMapCanvasMap( this );
122 
123  // project handling
125  this, &QgsMapCanvas::readProject );
128 
129  connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemeChanged, this, &QgsMapCanvas::mapThemeChanged );
130  connect( QgsProject::instance()->mapThemeCollection(), &QgsMapThemeCollection::mapThemesChanged, this, &QgsMapCanvas::projectThemesChanged );
131 
135  mSettings.setEllipsoid( QgsProject::instance()->ellipsoid() );
137  this, [ = ]
138  {
139  mSettings.setEllipsoid( QgsProject::instance()->ellipsoid() );
140  refresh();
141  } );
142  mSettings.setTransformContext( QgsProject::instance()->transformContext() );
144  this, [ = ]
145  {
146  mSettings.setTransformContext( QgsProject::instance()->transformContext() );
148  refresh();
149  } );
150 
151  //segmentation parameters
152  QgsSettings settings;
153  double segmentationTolerance = settings.value( QStringLiteral( "qgis/segmentationTolerance" ), "0.01745" ).toDouble();
154  QgsAbstractGeometry::SegmentationToleranceType toleranceType = settings.enumSettingValue( QStringLiteral( "qgis/segmentationToleranceType" ), QgsAbstractGeometry::MaximumAngle );
155  mSettings.setSegmentationTolerance( segmentationTolerance );
156  mSettings.setSegmentationToleranceType( toleranceType );
157 
158  mWheelZoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
159 
160  QSize s = viewport()->size();
161  mSettings.setOutputSize( s );
162  setSceneRect( 0, 0, s.width(), s.height() );
163  mScene->setSceneRect( QRectF( 0, 0, s.width(), s.height() ) );
164 
165  moveCanvasContents( true );
166 
167  connect( &mMapUpdateTimer, &QTimer::timeout, this, &QgsMapCanvas::mapUpdateTimeout );
168  mMapUpdateTimer.setInterval( 250 );
169 
170 #ifdef Q_OS_WIN
171  // Enable touch event on Windows.
172  // Qt on Windows needs to be told it can take touch events or else it ignores them.
173  grabGesture( Qt::PinchGesture );
174  viewport()->setAttribute( Qt::WA_AcceptTouchEvents );
175 #endif
176 
177  mPreviewEffect = new QgsPreviewEffect( this );
178  viewport()->setGraphicsEffect( mPreviewEffect );
179 
180  mZoomCursor = QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn );
181 
182  connect( &mAutoRefreshTimer, &QTimer::timeout, this, &QgsMapCanvas::autoRefreshTriggered );
183 
185 
186  setInteractive( false );
187 
188  // make sure we have the same default in QgsMapSettings and the scene's background brush
189  // (by default map settings has white bg color, scene background brush is black)
190  setCanvasColor( mSettings.backgroundColor() );
191 
192  refresh();
193 
194 } // QgsMapCanvas ctor
195 
196 
198 {
199  if ( mMapTool )
200  {
201  mMapTool->deactivate();
202  mMapTool = nullptr;
203  }
204  mLastNonZoomMapTool = nullptr;
205 
206  // rendering job may still end up writing into canvas map item
207  // so kill it before deleting canvas items
208  if ( mJob )
209  {
210  whileBlocking( mJob )->cancel();
211  delete mJob;
212  }
213 
214  // delete canvas items prior to deleting the canvas
215  // because they might try to update canvas when it's
216  // already being destructed, ends with segfault
217  QList<QGraphicsItem *> list = mScene->items();
218  QList<QGraphicsItem *>::iterator it = list.begin();
219  while ( it != list.end() )
220  {
221  QGraphicsItem *item = *it;
222  delete item;
223  ++it;
224  }
225 
226  mScene->deleteLater(); // crashes in python tests on windows
227 
228  // mCanvasProperties auto-deleted via QScopedPointer
229  // CanvasProperties struct has its own dtor for freeing resources
230 
231  delete mCache;
232 
233  delete mLabelingResults;
234 
235 } // dtor
236 
238 {
239  // do not go higher or lower than min max magnification ratio
240  double magnifierMin = QgsGuiUtils::CANVAS_MAGNIFICATION_MIN;
241  double magnifierMax = QgsGuiUtils::CANVAS_MAGNIFICATION_MAX;
242  factor = qBound( magnifierMin, factor, magnifierMax );
243 
244  // the magnifier widget is in integer percent
245  if ( !qgsDoubleNear( factor, mSettings.magnificationFactor(), 0.01 ) )
246  {
247  mSettings.setMagnificationFactor( factor );
248  refresh();
249  emit magnificationChanged( factor );
250  }
251 }
252 
254 {
255  return mSettings.magnificationFactor();
256 }
257 
259 {
260  mSettings.setFlag( QgsMapSettings::Antialiasing, flag );
261 } // anti aliasing
262 
264 {
265  mSettings.setFlag( QgsMapSettings::RenderMapTile, flag );
266 }
267 
269 {
270  QList<QgsMapLayer *> layers = mapSettings().layers();
271  if ( index >= 0 && index < ( int ) layers.size() )
272  return layers[index];
273  else
274  return nullptr;
275 }
276 
278 {
279  mCurrentLayer = layer;
280  emit currentLayerChanged( layer );
281 }
282 
283 double QgsMapCanvas::scale() const
284 {
285  return mapSettings().scale();
286 }
287 
289 {
290  return nullptr != mJob;
291 } // isDrawing
292 
293 // return the current coordinate transform based on the extents and
294 // device size
296 {
297  return &mapSettings().mapToPixel();
298 }
299 
300 void QgsMapCanvas::setLayers( const QList<QgsMapLayer *> &layers )
301 {
302  // following a theme => request denied!
303  if ( !mTheme.isEmpty() )
304  return;
305 
306  setLayersPrivate( layers );
307 }
308 
309 void QgsMapCanvas::setLayersPrivate( const QList<QgsMapLayer *> &layers )
310 {
311  QList<QgsMapLayer *> oldLayers = mSettings.layers();
312 
313  // update only if needed
314  if ( layers == oldLayers )
315  return;
316 
317  Q_FOREACH ( QgsMapLayer *layer, oldLayers )
318  {
319  disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapCanvas::layerRepaintRequested );
320  disconnect( layer, &QgsMapLayer::autoRefreshIntervalChanged, this, &QgsMapCanvas::updateAutoRefreshTimer );
321  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer ) )
322  {
324  }
325  }
326 
327  mSettings.setLayers( layers );
328 
329  Q_FOREACH ( QgsMapLayer *layer, layers )
330  {
331  if ( !layer )
332  continue;
333  connect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapCanvas::layerRepaintRequested );
334  connect( layer, &QgsMapLayer::autoRefreshIntervalChanged, this, &QgsMapCanvas::updateAutoRefreshTimer );
335  if ( QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( layer ) )
336  {
338  }
339  }
340 
341  QgsDebugMsg( "Layers have changed, refreshing" );
342  emit layersChanged();
343 
344  updateAutoRefreshTimer();
345  refresh();
346 }
347 
348 
350 {
351  return mSettings;
352 }
353 
355 {
356  if ( mSettings.destinationCrs() == crs )
357  return;
358 
359  // try to reproject current extent to the new one
360  QgsRectangle rect;
361  if ( !mSettings.visibleExtent().isEmpty() )
362  {
363  QgsCoordinateTransform transform( mSettings.destinationCrs(), crs, QgsProject::instance() );
364  try
365  {
366  rect = transform.transformBoundingBox( mSettings.visibleExtent() );
367  }
368  catch ( QgsCsException &e )
369  {
370  Q_UNUSED( e );
371  QgsDebugMsg( QString( "Transform error caught: %1" ).arg( e.what() ) );
372  }
373  }
374 
375  if ( !rect.isEmpty() )
376  {
377  setExtent( rect );
378  }
379 
380  mSettings.setDestinationCrs( crs );
381  updateScale();
382 
383  QgsDebugMsg( "refreshing after destination CRS changed" );
384  refresh();
385 
386  emit destinationCrsChanged();
387 }
388 
389 void QgsMapCanvas::setMapSettingsFlags( QgsMapSettings::Flags flags )
390 {
391  mSettings.setFlags( flags );
392  clearCache();
393  refresh();
394 }
395 
397 {
398  return mLabelingResults;
399 }
400 
402 {
403  if ( enabled == isCachingEnabled() )
404  return;
405 
406  if ( mJob && mJob->isActive() )
407  {
408  // wait for the current rendering to finish, before touching the cache
409  mJob->waitForFinished();
410  }
411 
412  if ( enabled )
413  {
414  mCache = new QgsMapRendererCache;
415  }
416  else
417  {
418  delete mCache;
419  mCache = nullptr;
420  }
421 }
422 
424 {
425  return nullptr != mCache;
426 }
427 
429 {
430  if ( mCache )
431  mCache->clear();
432 }
433 
435 {
436  mUseParallelRendering = enabled;
437 }
438 
440 {
441  return mUseParallelRendering;
442 }
443 
444 void QgsMapCanvas::setMapUpdateInterval( int timeMilliseconds )
445 {
446  mMapUpdateTimer.setInterval( timeMilliseconds );
447 }
448 
450 {
451  return mMapUpdateTimer.interval();
452 }
453 
454 
456 {
457  return mCurrentLayer;
458 }
459 
460 
462 {
463  if ( !mSettings.hasValidSettings() )
464  {
465  QgsDebugMsg( "CANVAS refresh - invalid settings -> nothing to do" );
466  return;
467  }
468 
469  if ( !mRenderFlag || mFrozen )
470  {
471  QgsDebugMsg( "CANVAS render flag off" );
472  return;
473  }
474 
475  if ( mRefreshScheduled )
476  {
477  QgsDebugMsg( "CANVAS refresh already scheduled" );
478  return;
479  }
480 
481  mRefreshScheduled = true;
482 
483  QgsDebugMsg( "CANVAS refresh scheduling" );
484 
485  // schedule a refresh
486  mRefreshTimer->start( 1 );
487 } // refresh
488 
489 void QgsMapCanvas::refreshMap()
490 {
491  Q_ASSERT( mRefreshScheduled );
492 
493  QgsDebugMsgLevel( "CANVAS refresh!", 3 );
494 
495  stopRendering(); // if any...
496  stopPreviewJobs();
497 
498  //build the expression context
499  QgsExpressionContext expressionContext;
500  expressionContext << QgsExpressionContextUtils::globalScope()
503  << new QgsExpressionContextScope( mExpressionContextScope );
504 
505  mSettings.setExpressionContext( expressionContext );
506  mSettings.setPathResolver( QgsProject::instance()->pathResolver() );
507 
508  if ( !mTheme.isEmpty() )
509  {
510  // IMPORTANT: we MUST set the layer style overrides here! (At the time of writing this
511  // comment) retrieving layer styles from the theme collection gives an XML snapshot of the
512  // current state of the style. If we had stored the style overrides earlier (such as in
513  // mapThemeChanged slot) then this xml could be out of date...
514  // TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
515  // just return the style name, we can instead set the overrides in mapThemeChanged and not here
516  mSettings.setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( mTheme ) );
517  }
518 
519  // create the renderer job
520  Q_ASSERT( !mJob );
521  mJobCanceled = false;
522  if ( mUseParallelRendering )
523  mJob = new QgsMapRendererParallelJob( mSettings );
524  else
525  mJob = new QgsMapRendererSequentialJob( mSettings );
526  connect( mJob, &QgsMapRendererJob::finished, this, &QgsMapCanvas::rendererJobFinished );
527  mJob->setCache( mCache );
528 
529  mJob->start();
530 
531  // from now on we can accept refresh requests again
532  // this must be reset only after the job has been started, because
533  // some providers (yes, it's you WCS and AMS!) during preparation
534  // do network requests and start an internal event loop, which may
535  // end up calling refresh() and would schedule another refresh,
536  // deleting the one we have just started.
537  mRefreshScheduled = false;
538 
539  mMapUpdateTimer.start();
540 
541  emit renderStarting();
542 }
543 
544 void QgsMapCanvas::mapThemeChanged( const QString &theme )
545 {
546  if ( theme == mTheme )
547  {
548  // set the canvas layers to match the new layers contained in the map theme
549  // NOTE: we do this when the theme layers change and not when we are refreshing the map
550  // as setLayers() sets up necessary connections to handle changes to the layers
551  setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
552  // IMPORTANT: we don't set the layer style overrides here! (At the time of writing this
553  // comment) retrieving layer styles from the theme collection gives an XML snapshot of the
554  // current state of the style. If changes were made to the style then this xml
555  // snapshot goes out of sync...
556  // TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
557  // just return the style name, we can instead set the overrides here and not in refreshMap()
558 
559  clearCache();
560  refresh();
561  }
562 }
563 
564 
565 void QgsMapCanvas::rendererJobFinished()
566 {
567  QgsDebugMsg( QString( "CANVAS finish! %1" ).arg( !mJobCanceled ) );
568 
569  mMapUpdateTimer.stop();
570 
571  // TODO: would be better to show the errors in message bar
572  Q_FOREACH ( const QgsMapRendererJob::Error &error, mJob->errors() )
573  {
574  QgsMessageLog::logMessage( error.layerID + " :: " + error.message, tr( "Rendering" ) );
575  }
576 
577  if ( !mJobCanceled )
578  {
579  // take labeling results before emitting renderComplete, so labeling map tools
580  // connected to signal work with correct results
581  if ( !mJob->usedCachedLabels() )
582  {
583  delete mLabelingResults;
584  mLabelingResults = mJob->takeLabelingResults();
585  }
586 
587  QImage img = mJob->renderedImage();
588 
589  // emit renderComplete to get our decorations drawn
590  QPainter p( &img );
591  emit renderComplete( &p );
592 
593  QgsSettings settings;
594  if ( settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
595  {
596  QString logMsg = tr( "Canvas refresh: %1 ms" ).arg( mJob->renderingTime() );
597  QgsMessageLog::logMessage( logMsg, tr( "Rendering" ) );
598  }
599 
600  if ( mDrawRenderingStats )
601  {
602  int w = img.width(), h = img.height();
603  QFont fnt = p.font();
604  fnt.setBold( true );
605  p.setFont( fnt );
606  int lh = p.fontMetrics().height() * 2;
607  QRect r( 0, h - lh, w, lh );
608  p.setPen( Qt::NoPen );
609  p.setBrush( QColor( 0, 0, 0, 110 ) );
610  p.drawRect( r );
611  p.setPen( Qt::white );
612  QString msg = QStringLiteral( "%1 :: %2 ms" ).arg( mUseParallelRendering ? "PARALLEL" : "SEQUENTIAL" ).arg( mJob->renderingTime() );
613  p.drawText( r, msg, QTextOption( Qt::AlignCenter ) );
614  }
615 
616  p.end();
617 
618  mMap->setContent( img, imageRect( img, mSettings ) );
619 
620  mLastLayerRenderTime.clear();
621  const auto times = mJob->perLayerRenderingTime();
622  for ( auto it = times.constBegin(); it != times.constEnd(); ++it )
623  {
624  mLastLayerRenderTime.insert( it.key()->id(), it.value() );
625  }
626  if ( mUsePreviewJobs )
627  startPreviewJobs();
628  }
629 
630  // now we are in a slot called from mJob - do not delete it immediately
631  // so the class is still valid when the execution returns to the class
632  mJob->deleteLater();
633  mJob = nullptr;
634 
635  emit mapCanvasRefreshed();
636 }
637 
638 void QgsMapCanvas::previewJobFinished()
639 {
640  QgsMapRendererQImageJob *job = qobject_cast<QgsMapRendererQImageJob *>( sender() );
641  Q_ASSERT( job );
642 
643  if ( mMap )
644  {
645  mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
646  mPreviewJobs.removeAll( job );
647 
648  int number = job->property( "number" ).toInt();
649  if ( number < 8 )
650  {
651  startPreviewJob( number + 1 );
652  }
653 
654  delete job;
655  }
656 }
657 
658 QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings )
659 {
660  // This is a hack to pass QgsMapCanvasItem::setRect what it
661  // expects (encoding of position and size of the item)
662  const QgsMapToPixel &m2p = mapSettings.mapToPixel();
663  QgsPointXY topLeft = m2p.toMapPoint( 0, 0 );
664  double res = m2p.mapUnitsPerPixel();
665  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + img.width()*res, topLeft.y() - img.height()*res );
666  return rect;
667 }
668 
670 {
671  return mUsePreviewJobs;
672 }
673 
675 {
676  mUsePreviewJobs = enabled;
677 }
678 
679 void QgsMapCanvas::mapUpdateTimeout()
680 {
681  if ( mJob )
682  {
683  const QImage &img = mJob->renderedImage();
684  mMap->setContent( img, imageRect( img, mSettings ) );
685  }
686 }
687 
689 {
690  if ( mJob )
691  {
692  QgsDebugMsg( "CANVAS stop rendering!" );
693  mJobCanceled = true;
694  disconnect( mJob, &QgsMapRendererJob::finished, this, &QgsMapCanvas::rendererJobFinished );
695  connect( mJob, &QgsMapRendererQImageJob::finished, mJob, &QgsMapRendererQImageJob::deleteLater );
696  mJob->cancelWithoutBlocking();
697  mJob = nullptr;
698  }
699  stopPreviewJobs();
700 }
701 
702 //the format defaults to "PNG" if not specified
703 void QgsMapCanvas::saveAsImage( const QString &fileName, QPixmap *theQPixmap, const QString &format )
704 {
705  QPainter painter;
706  QImage image;
707 
708  //
709  //check if the optional QPaintDevice was supplied
710  //
711  if ( theQPixmap )
712  {
713  image = theQPixmap->toImage();
714  painter.begin( &image );
715 
716  // render
717  QgsMapRendererCustomPainterJob job( mSettings, &painter );
718  job.start();
719  job.waitForFinished();
720  emit renderComplete( &painter );
721  }
722  else //use the map view
723  {
724  image = mMap->contentImage().copy();
725  painter.begin( &image );
726  }
727 
728  // draw annotations
729  QStyleOptionGraphicsItem option;
730  option.initFrom( this );
731  QGraphicsItem *item = nullptr;
732  QListIterator<QGraphicsItem *> i( items() );
733  i.toBack();
734  while ( i.hasPrevious() )
735  {
736  item = i.previous();
737 
738  if ( !item || dynamic_cast< QgsMapCanvasAnnotationItem * >( item ) )
739  {
740  continue;
741  }
742 
743  painter.save();
744 
745  QPointF itemScenePos = item->scenePos();
746  painter.translate( itemScenePos.x(), itemScenePos.y() );
747 
748  item->paint( &painter, &option );
749 
750  painter.restore();
751  }
752 
753  painter.end();
754  image.save( fileName, format.toLocal8Bit().data() );
755 
756  QFileInfo myInfo = QFileInfo( fileName );
757 
758  // build the world file name
759  QString outputSuffix = myInfo.suffix();
760  QString myWorldFileName = myInfo.absolutePath() + '/' + myInfo.baseName() + '.'
761  + outputSuffix.at( 0 ) + outputSuffix.at( myInfo.suffix().size() - 1 ) + 'w';
762  QFile myWorldFile( myWorldFileName );
763  if ( !myWorldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) //don't use QIODevice::Text
764  {
765  return;
766  }
767  QTextStream myStream( &myWorldFile );
769 } // saveAsImage
770 
771 
772 
774 {
775  return mapSettings().visibleExtent();
776 } // extent
777 
779 {
780  return mapSettings().fullExtent();
781 } // extent
782 
783 
784 void QgsMapCanvas::setExtent( const QgsRectangle &r, bool magnified )
785 {
786  QgsRectangle current = extent();
787 
788  if ( ( r == current ) && magnified )
789  return;
790 
791  if ( r.isEmpty() )
792  {
793  if ( !mSettings.hasValidSettings() )
794  {
795  // we can't even just move the map center
796  QgsDebugMsg( "Empty extent - ignoring" );
797  return;
798  }
799 
800  // ### QGIS 3: do not allow empty extent - require users to call setCenter() explicitly
801  QgsDebugMsg( "Empty extent - keeping old scale with new center!" );
802  setCenter( r.center() );
803  }
804  else
805  {
806  mSettings.setExtent( r, magnified );
807  }
808  emit extentsChanged();
809  updateScale();
810  if ( mLastExtent.size() > 20 )
811  mLastExtent.removeAt( 0 );
812 
813  //clear all extent items after current index
814  for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
815  {
816  mLastExtent.removeAt( i );
817  }
818 
819  mLastExtent.append( extent() );
820 
821  // adjust history to no more than 20
822  if ( mLastExtent.size() > 20 )
823  {
824  mLastExtent.removeAt( 0 );
825  }
826 
827  // the last item is the current extent
828  mLastExtentIndex = mLastExtent.size() - 1;
829 
830  // update controls' enabled state
831  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
832  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
833 } // setExtent
834 
836 {
838  double x = center.x();
839  double y = center.y();
840  setExtent(
841  QgsRectangle(
842  x - r.width() / 2.0, y - r.height() / 2.0,
843  x + r.width() / 2.0, y + r.height() / 2.0
844  ),
845  true
846  );
847 } // setCenter
848 
850 {
852  return r.center();
853 }
854 
855 
857 {
858  return mapSettings().rotation();
859 } // rotation
860 
861 void QgsMapCanvas::setRotation( double degrees )
862 {
863  double current = rotation();
864 
865  if ( degrees == current )
866  return;
867 
868  mSettings.setRotation( degrees );
869  emit rotationChanged( degrees );
870  emit extentsChanged(); // visible extent changes with rotation
871 } // setRotation
872 
873 
875 {
876  emit scaleChanged( mapSettings().scale() );
877 }
878 
879 
881 {
883  // If the full extent is an empty set, don't do the zoom
884  if ( !extent.isEmpty() )
885  {
886  // Add a 5% margin around the full extent
887  extent.scale( 1.05 );
888  setExtent( extent );
889  }
890  refresh();
891 
892 } // zoomToFullExtent
893 
894 
895 
897 {
898  if ( mLastExtentIndex > 0 )
899  {
900  mLastExtentIndex--;
901  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
902  emit extentsChanged();
903  updateScale();
904  refresh();
905  // update controls' enabled state
906  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
907  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
908  }
909 
910 } // zoomToPreviousExtent
911 
913 {
914  if ( mLastExtentIndex < mLastExtent.size() - 1 )
915  {
916  mLastExtentIndex++;
917  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
918  emit extentsChanged();
919  updateScale();
920  refresh();
921  // update controls' enabled state
922  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
923  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
924  }
925 }// zoomToNextExtent
926 
928 {
929  mLastExtent.clear(); // clear the zoom history list
930  mLastExtent.append( extent() ) ; // set the current extent in the list
931  mLastExtentIndex = mLastExtent.size() - 1;
932  // update controls' enabled state
933  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
934  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
935 }// clearExtentHistory
936 
938 {
939  if ( !layer )
940  {
941  // use current layer by default
942  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
943  }
944 
945  if ( !layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0 )
946  return;
947 
948  QgsRectangle rect = layer->boundingBoxOfSelected();
949  if ( rect.isNull() )
950  {
951  emit messageEmitted( tr( "Cannot zoom to selected feature(s)" ), tr( "No extent could be determined." ), Qgis::Warning );
952  return;
953  }
954 
955  rect = mapSettings().layerExtentToOutputExtent( layer, rect );
956  zoomToFeatureExtent( rect );
957 } // zoomToSelected
958 
960 {
961  // no selected features, only one selected point feature
962  //or two point features with the same x- or y-coordinates
963  if ( rect.isEmpty() )
964  {
965  // zoom in
966  QgsPointXY c = rect.center();
967  rect = extent();
968  rect.scale( 1.0, &c );
969  }
970  //zoom to an area
971  else
972  {
973  // Expand rect to give a bit of space around the selected
974  // objects so as to keep them clear of the map boundaries
975  // The same 5% should apply to all margins.
976  rect.scale( 1.05 );
977  }
978 
979  setExtent( rect );
980  refresh();
981 }
982 
984 {
985  if ( !layer )
986  {
987  return;
988  }
989 
990  QgsRectangle bbox;
991  QString errorMsg;
992  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
993  {
994  zoomToFeatureExtent( bbox );
995  }
996  else
997  {
998  emit messageEmitted( tr( "Zoom to feature id failed" ), errorMsg, Qgis::Warning );
999  }
1000 
1001 }
1002 
1004 {
1005  if ( !layer )
1006  {
1007  return;
1008  }
1009 
1010  QgsRectangle bbox;
1011  QString errorMsg;
1012  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
1013  {
1014  setCenter( bbox.center() );
1015  refresh();
1016  }
1017  else
1018  {
1019  emit messageEmitted( tr( "Pan to feature id failed" ), errorMsg, Qgis::Warning );
1020  }
1021 }
1022 
1023 bool QgsMapCanvas::boundingBoxOfFeatureIds( const QgsFeatureIds &ids, QgsVectorLayer *layer, QgsRectangle &bbox, QString &errorMsg ) const
1024 {
1025  QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFids( ids ).setSubsetOfAttributes( QgsAttributeList() ) );
1026  bbox.setMinimal();
1027  QgsFeature fet;
1028  int featureCount = 0;
1029  errorMsg.clear();
1030 
1031  while ( it.nextFeature( fet ) )
1032  {
1033  QgsGeometry geom = fet.geometry();
1034  if ( geom.isNull() )
1035  {
1036  errorMsg = tr( "Feature does not have a geometry" );
1037  }
1038  else if ( geom.constGet()->isEmpty() )
1039  {
1040  errorMsg = tr( "Feature geometry is empty" );
1041  }
1042  if ( !errorMsg.isEmpty() )
1043  {
1044  return false;
1045  }
1047  bbox.combineExtentWith( r );
1048  featureCount++;
1049  }
1050 
1051  if ( featureCount != ids.count() )
1052  {
1053  errorMsg = tr( "Feature not found" );
1054  return false;
1055  }
1056 
1057  return true;
1058 }
1059 
1061 {
1062  if ( !layer )
1063  {
1064  // use current layer by default
1065  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1066  }
1067 
1068  if ( !layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0 )
1069  return;
1070 
1071  QgsRectangle rect = layer->boundingBoxOfSelected();
1072  if ( rect.isNull() )
1073  {
1074  emit messageEmitted( tr( "Cannot pan to selected feature(s)" ), tr( "No extent could be determined." ), Qgis::Warning );
1075  return;
1076  }
1077 
1078  rect = mapSettings().layerExtentToOutputExtent( layer, rect );
1079  setCenter( rect.center() );
1080  refresh();
1081 }
1082 
1084  const QColor &color1, const QColor &color2,
1085  int flashes, int duration )
1086 {
1087  if ( !layer )
1088  {
1089  return;
1090  }
1091 
1092  QList< QgsGeometry > geoms;
1093 
1094  QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFids( ids ).setSubsetOfAttributes( QgsAttributeList() ) );
1095  QgsFeature fet;
1096  while ( it.nextFeature( fet ) )
1097  {
1098  if ( !fet.hasGeometry() )
1099  continue;
1100  geoms << fet.geometry();
1101  }
1102 
1103  flashGeometries( geoms, layer->crs(), color1, color2, flashes, duration );
1104 }
1105 
1106 void QgsMapCanvas::flashGeometries( const QList<QgsGeometry> &geometries, const QgsCoordinateReferenceSystem &crs, const QColor &color1, const QColor &color2, int flashes, int duration )
1107 {
1108  if ( geometries.isEmpty() )
1109  return;
1110 
1111  QgsWkbTypes::GeometryType geomType = QgsWkbTypes::geometryType( geometries.at( 0 ).wkbType() );
1112  QgsRubberBand *rb = new QgsRubberBand( this, geomType );
1113  for ( const QgsGeometry &geom : geometries )
1114  rb->addGeometry( geom, crs );
1115 
1116  if ( geomType == QgsWkbTypes::LineGeometry || geomType == QgsWkbTypes::PointGeometry )
1117  {
1118  rb->setWidth( 2 );
1119  rb->setSecondaryStrokeColor( QColor( 255, 255, 255 ) );
1120  }
1121  if ( geomType == QgsWkbTypes::PointGeometry )
1122  rb->setIcon( QgsRubberBand::ICON_CIRCLE );
1123 
1124  QColor startColor = color1;
1125  if ( !startColor.isValid() )
1126  {
1127  if ( geomType == QgsWkbTypes::PolygonGeometry )
1128  {
1129  startColor = rb->fillColor();
1130  }
1131  else
1132  {
1133  startColor = rb->strokeColor();
1134  }
1135  startColor.setAlpha( 255 );
1136  }
1137  QColor endColor = color2;
1138  if ( !endColor.isValid() )
1139  {
1140  endColor = startColor;
1141  endColor.setAlpha( 0 );
1142  }
1143 
1144 
1145  QVariantAnimation *animation = new QVariantAnimation( this );
1146  connect( animation, &QVariantAnimation::finished, this, [animation, rb]
1147  {
1148  animation->deleteLater();
1149  delete rb;
1150  } );
1151  connect( animation, &QPropertyAnimation::valueChanged, this, [rb, geomType]( const QVariant & value )
1152  {
1153  QColor c = value.value<QColor>();
1154  if ( geomType == QgsWkbTypes::PolygonGeometry )
1155  {
1156  rb->setFillColor( c );
1157  }
1158  else
1159  {
1160  rb->setStrokeColor( c );
1161  QColor c = rb->secondaryStrokeColor();
1162  c.setAlpha( c.alpha() );
1163  rb->setSecondaryStrokeColor( c );
1164  }
1165  rb->update();
1166  } );
1167 
1168  animation->setDuration( duration * flashes );
1169  animation->setStartValue( endColor );
1170  double midStep = 0.2 / flashes;
1171  for ( int i = 0; i < flashes; ++i )
1172  {
1173  double start = static_cast< double >( i ) / flashes;
1174  animation->setKeyValueAt( start + midStep, startColor );
1175  double end = static_cast< double >( i + 1 ) / flashes;
1176  if ( !qgsDoubleNear( end, 1.0 ) )
1177  animation->setKeyValueAt( end, endColor );
1178  }
1179  animation->setEndValue( endColor );
1180  animation->start();
1181 }
1182 
1183 void QgsMapCanvas::keyPressEvent( QKeyEvent *e )
1184 {
1185  if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
1186  {
1187  emit keyPressed( e );
1188  return;
1189  }
1190 
1191  if ( ! mCanvasProperties->mouseButtonDown )
1192  {
1193  // Don't want to interfer with mouse events
1194 
1195  QgsRectangle currentExtent = mapSettings().visibleExtent();
1196  double dx = std::fabs( currentExtent.width() / 4 );
1197  double dy = std::fabs( currentExtent.height() / 4 );
1198 
1199  switch ( e->key() )
1200  {
1201  case Qt::Key_Left:
1202  QgsDebugMsg( "Pan left" );
1203  setCenter( center() - QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1204  refresh();
1205  break;
1206 
1207  case Qt::Key_Right:
1208  QgsDebugMsg( "Pan right" );
1209  setCenter( center() + QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1210  refresh();
1211  break;
1212 
1213  case Qt::Key_Up:
1214  QgsDebugMsg( "Pan up" );
1215  setCenter( center() + QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1216  refresh();
1217  break;
1218 
1219  case Qt::Key_Down:
1220  QgsDebugMsg( "Pan down" );
1221  setCenter( center() - QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1222  refresh();
1223  break;
1224 
1225 
1226 
1227  case Qt::Key_Space:
1228  QgsDebugMsg( "Pressing pan selector" );
1229 
1230  //mCanvasProperties->dragging = true;
1231  if ( ! e->isAutoRepeat() )
1232  {
1233  QApplication::setOverrideCursor( Qt::ClosedHandCursor );
1234  mCanvasProperties->panSelectorDown = true;
1235  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1236  }
1237  break;
1238 
1239  case Qt::Key_PageUp:
1240  QgsDebugMsg( "Zoom in" );
1241  zoomIn();
1242  break;
1243 
1244  case Qt::Key_PageDown:
1245  QgsDebugMsg( "Zoom out" );
1246  zoomOut();
1247  break;
1248 
1249 #if 0
1250  case Qt::Key_P:
1251  mUseParallelRendering = !mUseParallelRendering;
1252  refresh();
1253  break;
1254 
1255  case Qt::Key_S:
1256  mDrawRenderingStats = !mDrawRenderingStats;
1257  refresh();
1258  break;
1259 #endif
1260 
1261  default:
1262  // Pass it on
1263  if ( mMapTool )
1264  {
1265  mMapTool->keyPressEvent( e );
1266  }
1267  else e->ignore();
1268 
1269  QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
1270  }
1271  }
1272 
1273  emit keyPressed( e );
1274 
1275 } //keyPressEvent()
1276 
1277 void QgsMapCanvas::keyReleaseEvent( QKeyEvent *e )
1278 {
1279  QgsDebugMsg( "keyRelease event" );
1280 
1281  switch ( e->key() )
1282  {
1283  case Qt::Key_Space:
1284  if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
1285  {
1286  QgsDebugMsg( "Releasing pan selector" );
1287  QApplication::restoreOverrideCursor();
1288  mCanvasProperties->panSelectorDown = false;
1289  panActionEnd( mCanvasProperties->mouseLastXY );
1290  }
1291  break;
1292 
1293  default:
1294  // Pass it on
1295  if ( mMapTool )
1296  {
1297  mMapTool->keyReleaseEvent( e );
1298  }
1299  else e->ignore();
1300 
1301  QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
1302  }
1303 
1304  emit keyReleased( e );
1305 
1306 } //keyReleaseEvent()
1307 
1308 
1310 {
1311  // call handler of current map tool
1312  if ( mMapTool )
1313  {
1314  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1315  mMapTool->canvasDoubleClickEvent( me.get() );
1316  }
1317 }// mouseDoubleClickEvent
1318 
1319 
1320 void QgsMapCanvas::beginZoomRect( QPoint pos )
1321 {
1322  mZoomRect.setRect( 0, 0, 0, 0 );
1323  QApplication::setOverrideCursor( mZoomCursor );
1324  mZoomDragging = true;
1325  mZoomRubberBand.reset( new QgsRubberBand( this, QgsWkbTypes::PolygonGeometry ) );
1326  QColor color( Qt::blue );
1327  color.setAlpha( 63 );
1328  mZoomRubberBand->setColor( color );
1329  mZoomRect.setTopLeft( pos );
1330 }
1331 
1332 void QgsMapCanvas::endZoomRect( QPoint pos )
1333 {
1334  mZoomDragging = false;
1335  mZoomRubberBand.reset( nullptr );
1336  QApplication::restoreOverrideCursor();
1337 
1338  // store the rectangle
1339  mZoomRect.setRight( pos.x() );
1340  mZoomRect.setBottom( pos.y() );
1341 
1342  if ( mZoomRect.width() < 5 && mZoomRect.height() < 5 )
1343  {
1344  //probably a mistake - would result in huge zoom!
1345  return;
1346  }
1347 
1348  //account for bottom right -> top left dragging
1349  mZoomRect = mZoomRect.normalized();
1350 
1351  // set center and zoom
1352  const QSize &zoomRectSize = mZoomRect.size();
1353  const QSize &canvasSize = mSettings.outputSize();
1354  double sfx = ( double )zoomRectSize.width() / canvasSize.width();
1355  double sfy = ( double )zoomRectSize.height() / canvasSize.height();
1356  double sf = std::max( sfx, sfy );
1357 
1358  QgsPointXY c = mSettings.mapToPixel().toMapCoordinates( mZoomRect.center() );
1359 
1360  zoomByFactor( sf, &c );
1361  refresh();
1362 }
1363 
1364 void QgsMapCanvas::mousePressEvent( QMouseEvent *e )
1365 {
1366  //use middle mouse button for panning, map tools won't receive any events in that case
1367  if ( e->button() == Qt::MidButton )
1368  {
1369  mCanvasProperties->panSelectorDown = true;
1370  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1371  }
1372  else
1373  {
1374  // call handler of current map tool
1375  if ( mMapTool )
1376  {
1377  if ( mMapTool->flags() & QgsMapTool::AllowZoomRect && e->button() == Qt::LeftButton
1378  && e->modifiers() & Qt::ShiftModifier )
1379  {
1380  beginZoomRect( e->pos() );
1381  return;
1382  }
1383  else
1384  {
1385  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1386  mMapTool->canvasPressEvent( me.get() );
1387  }
1388  }
1389  }
1390 
1391  if ( mCanvasProperties->panSelectorDown )
1392  {
1393  return;
1394  }
1395 
1396  mCanvasProperties->mouseButtonDown = true;
1397  mCanvasProperties->rubberStartPoint = e->pos();
1398 
1399 } // mousePressEvent
1400 
1401 
1402 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent *e )
1403 {
1404  //use middle mouse button for panning, map tools won't receive any events in that case
1405  if ( e->button() == Qt::MidButton )
1406  {
1407  mCanvasProperties->panSelectorDown = false;
1408  panActionEnd( mCanvasProperties->mouseLastXY );
1409  }
1410  else if ( e->button() == Qt::BackButton )
1411  {
1413  return;
1414  }
1415  else if ( e->button() == Qt::ForwardButton )
1416  {
1417  zoomToNextExtent();
1418  return;
1419  }
1420  else
1421  {
1422  if ( mZoomDragging && e->button() == Qt::LeftButton )
1423  {
1424  endZoomRect( e->pos() );
1425  return;
1426  }
1427 
1428  // call handler of current map tool
1429  if ( mMapTool )
1430  {
1431  // right button was pressed in zoom tool? return to previous non zoom tool
1432  if ( e->button() == Qt::RightButton && mMapTool->flags() & QgsMapTool::Transient )
1433  {
1434  QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
1435  QString( mLastNonZoomMapTool ? "not null." : "null." ) );
1436 
1437  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1438 
1439  // change to older non-zoom tool
1440  if ( mLastNonZoomMapTool
1441  && ( !( mLastNonZoomMapTool->flags() & QgsMapTool::EditTool )
1442  || ( vlayer && vlayer->isEditable() ) ) )
1443  {
1444  QgsMapTool *t = mLastNonZoomMapTool;
1445  mLastNonZoomMapTool = nullptr;
1446  setMapTool( t );
1447  }
1448  return;
1449  }
1450  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1451  mMapTool->canvasReleaseEvent( me.get() );
1452  }
1453  }
1454 
1455 
1456  mCanvasProperties->mouseButtonDown = false;
1457 
1458  if ( mCanvasProperties->panSelectorDown )
1459  return;
1460 
1461 } // mouseReleaseEvent
1462 
1463 void QgsMapCanvas::resizeEvent( QResizeEvent *e )
1464 {
1465  QGraphicsView::resizeEvent( e );
1466  mResizeTimer->start( 500 );
1467 
1468  QSize lastSize = viewport()->size();
1469 
1470  mSettings.setOutputSize( lastSize );
1471 
1472  mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1473 
1474  moveCanvasContents( true );
1475 
1476  updateScale();
1477 
1478  //refresh();
1479 
1480  emit extentsChanged();
1481 }
1482 
1483 void QgsMapCanvas::paintEvent( QPaintEvent *e )
1484 {
1485  // no custom event handling anymore
1486 
1487  QGraphicsView::paintEvent( e );
1488 } // paintEvent
1489 
1491 {
1492  QList<QGraphicsItem *> list = mScene->items();
1493  QList<QGraphicsItem *>::iterator it = list.begin();
1494  while ( it != list.end() )
1495  {
1496  QgsMapCanvasItem *item = dynamic_cast<QgsMapCanvasItem *>( *it );
1497 
1498  if ( item )
1499  {
1500  item->updatePosition();
1501  }
1502 
1503  ++it;
1504  }
1505 }
1506 
1507 
1508 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
1509 {
1510  // Zoom the map canvas in response to a mouse wheel event. Moving the
1511  // wheel forward (away) from the user zooms in
1512 
1513  QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
1514 
1515  if ( mMapTool )
1516  {
1517  mMapTool->wheelEvent( e );
1518  if ( e->isAccepted() )
1519  return;
1520  }
1521 
1522  double zoomFactor = mWheelZoomFactor;
1523 
1524  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1525  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( e->angleDelta().y() );
1526 
1527  if ( e->modifiers() & Qt::ControlModifier )
1528  {
1529  //holding ctrl while wheel zooming results in a finer zoom
1530  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1531  }
1532 
1533  double signedWheelFactor = e->angleDelta().y() > 0 ? 1 / zoomFactor : zoomFactor;
1534 
1535  // zoom map to mouse cursor by scaling
1536  QgsPointXY oldCenter = center();
1537  QgsPointXY mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
1538  QgsPointXY newCenter( mousePos.x() + ( ( oldCenter.x() - mousePos.x() ) * signedWheelFactor ),
1539  mousePos.y() + ( ( oldCenter.y() - mousePos.y() ) * signedWheelFactor ) );
1540 
1541  zoomByFactor( signedWheelFactor, &newCenter );
1542  e->accept();
1543 }
1544 
1545 void QgsMapCanvas::setWheelFactor( double factor )
1546 {
1547  mWheelZoomFactor = factor;
1548 }
1549 
1551 {
1552  // magnification is alreday handled in zoomByFactor
1553  zoomByFactor( 1 / mWheelZoomFactor );
1554 }
1555 
1557 {
1558  // magnification is alreday handled in zoomByFactor
1559  zoomByFactor( mWheelZoomFactor );
1560 }
1561 
1562 void QgsMapCanvas::zoomScale( double newScale )
1563 {
1564  zoomByFactor( newScale / scale() );
1565 }
1566 
1567 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
1568 {
1569  double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1570 
1571  if ( mScaleLocked )
1572  {
1574  }
1575  else
1576  {
1577  // transform the mouse pos to map coordinates
1580  r.scale( scaleFactor, &center );
1581  setExtent( r, true );
1582  refresh();
1583  }
1584 }
1585 
1586 void QgsMapCanvas::setScaleLocked( bool isLocked )
1587 {
1588  mScaleLocked = isLocked;
1589 }
1590 
1591 void QgsMapCanvas::mouseMoveEvent( QMouseEvent *e )
1592 {
1593  mCanvasProperties->mouseLastXY = e->pos();
1594 
1595  if ( mCanvasProperties->panSelectorDown )
1596  {
1597  panAction( e );
1598  }
1599  else if ( mZoomDragging )
1600  {
1601  mZoomRect.setBottomRight( e->pos() );
1602  mZoomRubberBand->setToCanvasRectangle( mZoomRect );
1603  mZoomRubberBand->show();
1604  }
1605  else
1606  {
1607  // call handler of current map tool
1608  if ( mMapTool )
1609  {
1610  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1611  mMapTool->canvasMoveEvent( me.get() );
1612  }
1613  }
1614 
1615  // show x y on status bar
1616  QPoint xy = e->pos();
1618  emit xyCoordinates( coord );
1619 }
1620 
1621 void QgsMapCanvas::setMapTool( QgsMapTool *tool, bool clean )
1622 {
1623  if ( !tool )
1624  return;
1625 
1626  if ( mMapTool )
1627  {
1628  if ( clean )
1629  mMapTool->clean();
1630 
1631  disconnect( mMapTool, &QObject::destroyed, this, &QgsMapCanvas::mapToolDestroyed );
1632  mMapTool->deactivate();
1633  }
1634 
1635  if ( ( tool->flags() & QgsMapTool::Transient )
1636  && mMapTool && !( mMapTool->flags() & QgsMapTool::Transient ) )
1637  {
1638  // if zoom or pan tool will be active, save old tool
1639  // to bring it back on right click
1640  // (but only if it wasn't also zoom or pan tool)
1641  mLastNonZoomMapTool = mMapTool;
1642  }
1643  else
1644  {
1645  mLastNonZoomMapTool = nullptr;
1646  }
1647 
1648  QgsMapTool *oldTool = mMapTool;
1649 
1650  // set new map tool and activate it
1651  mMapTool = tool;
1652  if ( mMapTool )
1653  {
1654  connect( mMapTool, &QObject::destroyed, this, &QgsMapCanvas::mapToolDestroyed );
1655  mMapTool->activate();
1656  }
1657 
1658  emit mapToolSet( mMapTool, oldTool );
1659 } // setMapTool
1660 
1662 {
1663  if ( mMapTool && mMapTool == tool )
1664  {
1665  mMapTool->deactivate();
1666  mMapTool = nullptr;
1667  emit mapToolSet( nullptr, mMapTool );
1668  setCursor( Qt::ArrowCursor );
1669  }
1670 
1671  if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1672  {
1673  mLastNonZoomMapTool = nullptr;
1674  }
1675 }
1676 
1677 void QgsMapCanvas::setCanvasColor( const QColor &color )
1678 {
1679  if ( canvasColor() == color )
1680  return;
1681 
1682  // background of map's pixmap
1683  mSettings.setBackgroundColor( color );
1684 
1685  // background of the QGraphicsView
1686  QBrush bgBrush( color );
1687  setBackgroundBrush( bgBrush );
1688 #if 0
1689  QPalette palette;
1690  palette.setColor( backgroundRole(), color );
1691  setPalette( palette );
1692 #endif
1693 
1694  // background of QGraphicsScene
1695  mScene->setBackgroundBrush( bgBrush );
1696 
1697  emit canvasColorChanged();
1698 }
1699 
1701 {
1702  return mScene->backgroundBrush().color();
1703 }
1704 
1705 void QgsMapCanvas::setSelectionColor( const QColor &color )
1706 {
1707  mSettings.setSelectionColor( color );
1708 }
1709 
1711 {
1712  return mSettings.selectionColor();
1713 }
1714 
1716 {
1717  return mapSettings().layers().size();
1718 } // layerCount
1719 
1720 
1721 QList<QgsMapLayer *> QgsMapCanvas::layers() const
1722 {
1723  return mapSettings().layers();
1724 }
1725 
1727 {
1728  // called when a layer has changed visibility setting
1729  refresh();
1730 }
1731 
1732 void QgsMapCanvas::freeze( bool frozen )
1733 {
1734  mFrozen = frozen;
1735 }
1736 
1738 {
1739  return mFrozen;
1740 }
1741 
1743 {
1744  return mapSettings().mapUnitsPerPixel();
1745 }
1746 
1748 {
1749  return mapSettings().mapUnits();
1750 }
1751 
1752 QMap<QString, QString> QgsMapCanvas::layerStyleOverrides() const
1753 {
1754  return mSettings.layerStyleOverrides();
1755 }
1756 
1757 void QgsMapCanvas::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
1758 {
1759  if ( overrides == mSettings.layerStyleOverrides() )
1760  return;
1761 
1762  mSettings.setLayerStyleOverrides( overrides );
1763  clearCache();
1765 }
1766 
1767 void QgsMapCanvas::setTheme( const QString &theme )
1768 {
1769  if ( mTheme == theme )
1770  return;
1771 
1772  clearCache();
1773  if ( theme.isEmpty() || !QgsProject::instance()->mapThemeCollection()->hasMapTheme( theme ) )
1774  {
1775  mTheme.clear();
1776  mSettings.setLayerStyleOverrides( QMap< QString, QString>() );
1777  setLayers( QgsProject::instance()->mapThemeCollection()->masterVisibleLayers() );
1778  emit themeChanged( QString() );
1779  }
1780  else
1781  {
1782  mTheme = theme;
1783  setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
1784  emit themeChanged( theme );
1785  }
1786 }
1787 
1789 {
1790  mRenderFlag = flag;
1791 
1792  if ( mRenderFlag )
1793  {
1794  refresh();
1795  }
1796  else
1797  stopRendering();
1798 }
1799 
1800 #if 0
1801 void QgsMapCanvas::connectNotify( const char *signal )
1802 {
1803  Q_UNUSED( signal );
1804  QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
1805 } //connectNotify
1806 #endif
1807 
1808 void QgsMapCanvas::layerRepaintRequested( bool deferred )
1809 {
1810  if ( !deferred )
1811  refresh();
1812 }
1813 
1814 void QgsMapCanvas::autoRefreshTriggered()
1815 {
1816  if ( mJob )
1817  {
1818  // canvas is currently being redrawn, so we skip this auto refresh
1819  // otherwise we could get stuck in the situation where an auto refresh is triggered
1820  // too often to allow the canvas to ever finish rendering
1821  return;
1822  }
1823 
1824  refresh();
1825 }
1826 
1827 void QgsMapCanvas::updateAutoRefreshTimer()
1828 {
1829  // min auto refresh interval stores the smallest interval between layer auto refreshes. We automatically
1830  // trigger a map refresh on this minimum interval
1831  int minAutoRefreshInterval = -1;
1832  Q_FOREACH ( QgsMapLayer *layer, mSettings.layers() )
1833  {
1834  if ( layer->hasAutoRefreshEnabled() && layer->autoRefreshInterval() > 0 )
1835  minAutoRefreshInterval = minAutoRefreshInterval > 0 ? std::min( layer->autoRefreshInterval(), minAutoRefreshInterval ) : layer->autoRefreshInterval();
1836  }
1837 
1838  if ( minAutoRefreshInterval > 0 )
1839  {
1840  mAutoRefreshTimer.setInterval( minAutoRefreshInterval );
1841  mAutoRefreshTimer.start();
1842  }
1843  else
1844  {
1845  mAutoRefreshTimer.stop();
1846  }
1847 }
1848 
1849 void QgsMapCanvas::projectThemesChanged()
1850 {
1851  if ( mTheme.isEmpty() )
1852  return;
1853 
1854  if ( !QgsProject::instance()->mapThemeCollection()->hasMapTheme( mTheme ) )
1855  {
1856  // theme has been removed - stop following
1857  setTheme( QString() );
1858  }
1859 
1860 }
1861 
1863 {
1864  return mMapTool;
1865 }
1866 
1867 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
1868 {
1869  // move map image and other items to standard position
1870  moveCanvasContents( true ); // true means reset
1871 
1872  // use start and end box points to calculate the extent
1873  QgsPointXY start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
1875 
1876  // modify the center
1877  double dx = end.x() - start.x();
1878  double dy = end.y() - start.y();
1879  QgsPointXY c = center();
1880  c.set( c.x() - dx, c.y() - dy );
1881  setCenter( c );
1882 
1883  refresh();
1884 }
1885 
1886 void QgsMapCanvas::panAction( QMouseEvent *e )
1887 {
1888  Q_UNUSED( e );
1889 
1890  // move all map canvas items
1892 }
1893 
1895 {
1896  QPoint pnt( 0, 0 );
1897  if ( !reset )
1898  pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
1899 
1900  setSceneRect( -pnt.x(), -pnt.y(), viewport()->size().width(), viewport()->size().height() );
1901 }
1902 
1904 {
1905  return mCanvasProperties->mouseLastXY;
1906 }
1907 
1908 void QgsMapCanvas::setPreviewModeEnabled( bool previewEnabled )
1909 {
1910  if ( !mPreviewEffect )
1911  {
1912  return;
1913  }
1914 
1915  mPreviewEffect->setEnabled( previewEnabled );
1916 }
1917 
1919 {
1920  if ( !mPreviewEffect )
1921  {
1922  return false;
1923  }
1924 
1925  return mPreviewEffect->isEnabled();
1926 }
1927 
1929 {
1930  if ( !mPreviewEffect )
1931  {
1932  return;
1933  }
1934 
1935  mPreviewEffect->setMode( mode );
1936 }
1937 
1939 {
1940  if ( !mPreviewEffect )
1941  {
1943  }
1944 
1945  return mPreviewEffect->mode();
1946 }
1947 
1949 {
1950  if ( !mSnappingUtils )
1951  {
1952  // associate a dummy instance, but better than null pointer
1953  QgsMapCanvas *c = const_cast<QgsMapCanvas *>( this );
1954  c->mSnappingUtils = new QgsMapCanvasSnappingUtils( c, c );
1955  }
1956  return mSnappingUtils;
1957 }
1958 
1960 {
1961  mSnappingUtils = utils;
1962 }
1963 
1964 void QgsMapCanvas::readProject( const QDomDocument &doc )
1965 {
1966  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "mapcanvas" ) );
1967  if ( nodes.count() )
1968  {
1969  QDomNode node = nodes.item( 0 );
1970 
1971  // Search the specific MapCanvas node using the name
1972  if ( nodes.count() > 1 )
1973  {
1974  for ( int i = 0; i < nodes.size(); ++i )
1975  {
1976  QDomElement elementNode = nodes.at( i ).toElement();
1977 
1978  if ( elementNode.hasAttribute( QStringLiteral( "name" ) ) && elementNode.attribute( QStringLiteral( "name" ) ) == objectName() )
1979  {
1980  node = nodes.at( i );
1981  break;
1982  }
1983  }
1984  }
1985 
1986  QgsMapSettings tmpSettings;
1987  tmpSettings.readXml( node );
1988  if ( objectName() != QStringLiteral( "theMapCanvas" ) )
1989  {
1990  // never manually set the crs for the main canvas - this is instead connected to the project CRS
1991  setDestinationCrs( tmpSettings.destinationCrs() );
1992  }
1993  setExtent( tmpSettings.extent() );
1994  setRotation( tmpSettings.rotation() );
1996 
1997  clearExtentHistory(); // clear the extent history on project load
1998 
1999  QDomElement elem = node.toElement();
2000  if ( elem.hasAttribute( QStringLiteral( "theme" ) ) )
2001  {
2002  if ( QgsProject::instance()->mapThemeCollection()->hasMapTheme( elem.attribute( QStringLiteral( "theme" ) ) ) )
2003  {
2004  setTheme( elem.attribute( QStringLiteral( "theme" ) ) );
2005  }
2006  }
2007  setAnnotationsVisible( elem.attribute( QStringLiteral( "annotationsVisible" ), QStringLiteral( "1" ) ).toInt() );
2008  }
2009  else
2010  {
2011  QgsDebugMsg( "Couldn't read mapcanvas information from project" );
2012  }
2013 }
2014 
2015 void QgsMapCanvas::writeProject( QDomDocument &doc )
2016 {
2017  // create node "mapcanvas" and call mMapRenderer->writeXml()
2018 
2019  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
2020  if ( !nl.count() )
2021  {
2022  QgsDebugMsg( "Unable to find qgis element in project file" );
2023  return;
2024  }
2025  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
2026 
2027  QDomElement mapcanvasNode = doc.createElement( QStringLiteral( "mapcanvas" ) );
2028  mapcanvasNode.setAttribute( QStringLiteral( "name" ), objectName() );
2029  if ( !mTheme.isEmpty() )
2030  mapcanvasNode.setAttribute( QStringLiteral( "theme" ), mTheme );
2031  mapcanvasNode.setAttribute( QStringLiteral( "annotationsVisible" ), mAnnotationsVisible );
2032  qgisNode.appendChild( mapcanvasNode );
2033 
2034  mSettings.writeXml( mapcanvasNode, doc );
2035  // TODO: store only units, extent, projections, dest CRS
2036 }
2037 
2038 #if 0
2039 void QgsMapCanvas::getDatumTransformInfo( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
2040 {
2041  if ( !source.isValid() || !destination.isValid() )
2042  return;
2043 
2044  //check if default datum transformation available
2045  QgsSettings s;
2046  QString settingsString = "/Projections/" + source.authid() + "//" + destination.authid();
2047  QVariant defaultSrcTransform = s.value( settingsString + "_srcTransform" );
2048  QVariant defaultDestTransform = s.value( settingsString + "_destTransform" );
2049  if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
2050  {
2051  int sourceDatumTransform = defaultSrcTransform.toInt();
2052  int destinationDatumTransform = defaultDestTransform.toInt();
2053 
2055  context.addSourceDestinationDatumTransform( source, destination, sourceDatumTransform, destinationDatumTransform );
2057  return;
2058  }
2059 
2060  if ( !s.value( QStringLiteral( "/Projections/showDatumTransformDialog" ), false ).toBool() )
2061  {
2062  return;
2063  }
2064 
2065  //if several possibilities: present dialog
2066  QgsDatumTransformDialog d( source, destination );
2067  if ( d.availableTransformationCount() > 1 )
2068  d.exec();
2069 }
2070 #endif
2071 
2072 void QgsMapCanvas::zoomByFactor( double scaleFactor, const QgsPointXY *center )
2073 {
2074  if ( mScaleLocked )
2075  {
2076  // zoom map to mouse cursor by magnifying
2078  }
2079  else
2080  {
2082  r.scale( scaleFactor, center );
2083  setExtent( r, true );
2084  refresh();
2085  }
2086 }
2087 
2089 {
2090  // Find out which layer it was that sent the signal.
2091  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
2092  emit selectionChanged( layer );
2093  refresh();
2094 }
2095 
2096 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent *e )
2097 {
2098  // By default graphics view delegates the drag events to graphics items.
2099  // But we do not want that and by ignoring the drag enter we let the
2100  // parent (e.g. QgisApp) to handle drops of map layers etc.
2101  e->ignore();
2102 }
2103 
2104 void QgsMapCanvas::mapToolDestroyed()
2105 {
2106  QgsDebugMsg( "maptool destroyed" );
2107  mMapTool = nullptr;
2108 }
2109 
2110 bool QgsMapCanvas::event( QEvent *e )
2111 {
2112  if ( !QTouchDevice::devices().empty() )
2113  {
2114  if ( e->type() == QEvent::Gesture )
2115  {
2116  // call handler of current map tool
2117  if ( mMapTool )
2118  {
2119  return mMapTool->gestureEvent( static_cast<QGestureEvent *>( e ) );
2120  }
2121  }
2122  }
2123 
2124  // pass other events to base class
2125  return QGraphicsView::event( e );
2126 }
2127 
2129 {
2130  // reload all layers in canvas
2131  for ( int i = 0; i < layerCount(); i++ )
2132  {
2133  QgsMapLayer *l = layer( i );
2134  if ( l )
2135  l->reload();
2136  }
2137 
2138  // clear the cache
2139  clearCache();
2140 
2141  // and then refresh
2142  refresh();
2143 }
2144 
2146 {
2147  while ( mRefreshScheduled || mJob )
2148  {
2149  QgsApplication::processEvents();
2150  }
2151 }
2152 
2154 {
2155  mSettings.setSegmentationTolerance( tolerance );
2156 }
2157 
2159 {
2160  mSettings.setSegmentationToleranceType( type );
2161 }
2162 
2163 QList<QgsMapCanvasAnnotationItem *> QgsMapCanvas::annotationItems() const
2164 {
2165  QList<QgsMapCanvasAnnotationItem *> annotationItemList;
2166  QList<QGraphicsItem *> itemList = mScene->items();
2167  QList<QGraphicsItem *>::iterator it = itemList.begin();
2168  for ( ; it != itemList.end(); ++it )
2169  {
2170  QgsMapCanvasAnnotationItem *aItem = dynamic_cast< QgsMapCanvasAnnotationItem *>( *it );
2171  if ( aItem )
2172  {
2173  annotationItemList.push_back( aItem );
2174  }
2175  }
2176 
2177  return annotationItemList;
2178 }
2179 
2181 {
2182  mAnnotationsVisible = show;
2183  Q_FOREACH ( QgsMapCanvasAnnotationItem *item, annotationItems() )
2184  {
2185  item->setVisible( show );
2186  }
2187 }
2188 
2190 {
2191  mSettings.setLabelingEngineSettings( settings );
2192 }
2193 
2195 {
2196  return mSettings.labelingEngineSettings();
2197 }
2198 
2199 void QgsMapCanvas::startPreviewJobs()
2200 {
2201  stopPreviewJobs(); //just in case still running
2202  schedulePreviewJob( 0 );
2203 }
2204 
2205 void QgsMapCanvas::startPreviewJob( int number )
2206 {
2207  QgsRectangle mapRect = mSettings.visibleExtent();
2208 
2209  if ( number == 4 )
2210  number += 1;
2211 
2212  int j = number / 3;
2213  int i = number % 3;
2214 
2215  //copy settings, only update extent
2216  QgsMapSettings jobSettings = mSettings;
2217 
2218  double dx = ( i - 1 ) * mapRect.width();
2219  double dy = ( 1 - j ) * mapRect.height();
2220  QgsRectangle jobExtent = mapRect;
2221 
2222  jobExtent.setXMaximum( jobExtent.xMaximum() + dx );
2223  jobExtent.setXMinimum( jobExtent.xMinimum() + dx );
2224  jobExtent.setYMaximum( jobExtent.yMaximum() + dy );
2225  jobExtent.setYMinimum( jobExtent.yMinimum() + dy );
2226 
2227  jobSettings.setExtent( jobExtent );
2228  jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );
2229  jobSettings.setFlag( QgsMapSettings::RenderPreviewJob, true );
2230 
2231  // truncate preview layers to fast layers
2232  const QList<QgsMapLayer *> layers = jobSettings.layers();
2233  QList< QgsMapLayer * > previewLayers;
2235  context.maxRenderingTimeMs = MAXIMUM_LAYER_PREVIEW_TIME_MS;
2236  for ( QgsMapLayer *layer : layers )
2237  {
2238  context.lastRenderingTimeMs = mLastLayerRenderTime.value( layer->id(), 0 );
2239  if ( !layer->dataProvider()->renderInPreview( context ) )
2240  {
2241  QgsDebugMsgLevel( QString( "Layer %1 not rendered because it does not match the renderInPreview criterion %2" ).arg( layer->id() ).arg( mLastLayerRenderTime.value( layer->id() ) ), 3 );
2242  continue;
2243  }
2244 
2245  previewLayers << layer;
2246  }
2247  jobSettings.setLayers( previewLayers );
2248 
2249  QgsMapRendererQImageJob *job = new QgsMapRendererSequentialJob( jobSettings );
2250  job->setProperty( "number", number );
2251  mPreviewJobs.append( job );
2252  connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
2253  job->start();
2254 }
2255 
2256 void QgsMapCanvas::stopPreviewJobs()
2257 {
2258  mPreviewTimer.stop();
2259  QList< QgsMapRendererQImageJob * >::const_iterator it = mPreviewJobs.constBegin();
2260  for ( ; it != mPreviewJobs.constEnd(); ++it )
2261  {
2262  if ( *it )
2263  {
2264  disconnect( *it, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
2265  connect( *it, &QgsMapRendererQImageJob::finished, *it, &QgsMapRendererQImageJob::deleteLater );
2266  ( *it )->cancelWithoutBlocking();
2267  }
2268  }
2269  mPreviewJobs.clear();
2270 }
2271 
2272 void QgsMapCanvas::schedulePreviewJob( int number )
2273 {
2274  mPreviewTimer.setSingleShot( true );
2275  mPreviewTimer.setInterval( PREVIEW_JOB_DELAY_MS );
2276  disconnect( mPreviewTimerConnection );
2277  mPreviewTimerConnection = connect( &mPreviewTimer, &QTimer::timeout, this, [ = ]()
2278  {
2279  startPreviewJob( number );
2280  }
2281  );
2282  mPreviewTimer.start();
2283 }
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
bool previewJobsEnabled() const
Returns true if canvas map preview jobs (low priority render jobs which render portions of the view j...
Wrapper for iterator of features from vector data provider or vector layer.
void updateCanvasItemPositions()
called on resize or changed extent to notify canvas items to change their rectangle ...
int autoRefreshInterval
Definition: qgsmaplayer.h:61
void finished()
emitted when asynchronous rendering is finished (or canceled).
void setParallelRenderingEnabled(bool enabled)
Set whether the layers are rendered in parallel or sequentially.
void set(double x, double y)
Sets the x and y value of the point.
Definition: qgspointxy.h:119
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
QPoint mouseLastXY
Last seen point of the mouse.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns global labeling engine settings from the internal map settings.
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Base class for all map layer types.
Definition: qgsmaplayer.h:56
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
Job implementation that renders everything sequentially using a custom painter.
std::unique_ptr< CanvasProperties > mCanvasProperties
Handle pattern for implementation object.
Definition: qgsmapcanvas.h:871
virtual bool isEmpty() const
Returns true if the geometry is empty.
void setRotation(double degrees)
Set the rotation of the map canvas in clockwise degrees.
virtual void canvasMoveEvent(QgsMapMouseEvent *e)
Mouse move event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:148
void setRenderFlag(bool flag)
Sets whether a user has disabled canvas renders via the GUI.
int mapUpdateInterval() const
Find out how often map preview should be updated while it is being rendered (in milliseconds) ...
QList< QgsMapCanvasAnnotationItem * > annotationItems() const
Returns a list of all annotation items in the canvas.
void zoomToNextExtent()
Zoom to the next extent (view)
bool hasMapTheme(const QString &name) const
Returns whether a map theme with a matching name exists.
void zoomWithCenter(int x, int y, bool zoomIn)
Zooms in/out with a given center.
void setCanvasColor(const QColor &_newVal)
Write property of QColor bgColor.
void setCenter(const QgsPointXY &center)
Set the center of the map canvas, in geographical coordinates.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setSegmentationToleranceType(QgsAbstractGeometry::SegmentationToleranceType type)
Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the coordinate transform context, which stores various information regarding which datum transfo...
QList< QgsMapLayer * > layers() const
Return the list of layers shown within the map canvas.
bool isNull() const
Returns true if the geometry is null (ie, contains no underlying geometry accessible via geometry() )...
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Sets the stored overrides of styles for rendering layers.
double magnificationFactor() const
Return the magnification factor.
double rotation() const
Returns the rotation of the resulting map image, in degrees clockwise.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:94
void clearExtentHistory()
This class is a composition of two QSettings instances:
Definition: qgssettings.h:57
Maximum angle between generating radii (lines from arc center to output vertices) ...
bool event(QEvent *e) override
Overridden standard event to be gestures aware.
QColor selectionColor() const
Returns color for selected features.
bool mouseButtonDown
Flag to indicate status of mouse button.
void wheelEvent(QWheelEvent *e) override
Overridden mouse wheel event.
void canvasColorChanged()
Emitted when canvas background color changes.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:544
void stopRendering()
stop rendering (if there is any right now)
double y
Definition: qgspointxy.h:48
void setPreviewJobsEnabled(bool enabled)
Sets whether canvas map preview jobs (low priority render jobs which render portions of the view just...
A class to represent a 2D point.
Definition: qgspointxy.h:43
double rotation() const
Get the current map canvas rotation in clockwise degrees.
QgsPreviewEffect::PreviewMode previewMode() const
Returns the current preview mode for the map canvas.
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
int selectedFeatureCount() const
The number of features that are selected in this layer.
QColor backgroundColor() const
Get the background color of the map.
void keyPressEvent(QKeyEvent *e) override
Overridden key press event.
void zoomToFeatureExtent(QgsRectangle &rect)
Zooms to feature extent.
virtual void reload()
Synchronises with changes in the datasource.
Definition: qgsmaplayer.h:386
Allow zooming by rectangle (by holding shift and dragging) while the tool is active.
Definition: qgsmaptool.h:95
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
void enableAntiAliasing(bool flag)
used to determine if anti-aliasing is enabled or not
An abstract class for items that can be placed on the map canvas.
void setCurrentLayer(QgsMapLayer *layer)
int layerCount() const
return number of layers on the map
Errors errors() const
List of errors that happened during the rendering job - available when the rendering has been finishe...
void moveCanvasContents(bool reset=false)
called when panning is in action, reset indicates end of panning
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
void setFlags(QgsMapSettings::Flags flags)
Set combination of flags that will be used for rendering.
void setAnnotationsVisible(bool visible)
Sets whether annotations are visible in the canvas.
constexpr double CANVAS_MAGNIFICATION_MAX
Maximum magnification level allowed in map canvases.
Definition: qgsguiutils.h:69
void readProject(const QDomDocument &)
called to read map canvas settings from project
bool panSelectorDown
Flag to indicate the pan selector key is held down by user.
void refresh()
Repaints the canvas map.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:111
void renderComplete(QPainter *)
Emitted when the canvas has rendered.
Snapping utils instance that is connected to a canvas and updates the configuration (map settings + c...
bool isCachingEnabled() const
Check whether images of rendered layers are curerently being cached.
void setLayerStyleOverrides(const QMap< QString, QString > &overrides)
Set map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
QgsMapTool * mapTool()
Returns the currently active tool.
SegmentationToleranceType
Segmentation tolerance as maximum angle or maximum difference between approximation and circle...
QList< QgsMapLayer * > layers() const
Get list of layers for map rendering The layers are stored in the reverse order of how they are rende...
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:62
void mousePressEvent(QMouseEvent *e) override
Overridden mouse press event.
bool hasGeometry() const
Returns true if the feature has an associated geometry.
Definition: qgsfeature.cpp:190
virtual Flags flags() const
Returns the flags for the map tool.
Definition: qgsmaptool.h:103
void mapThemesChanged()
Emitted when map themes within the collection are changed.
bool isEditable() const override
Returns true if the provider is in editing mode.
void setSegmentationTolerance(double tolerance)
Sets the segmentation tolerance applied when rendering curved geometries.
virtual QImage renderedImage()=0
Get a preview/resulting image.
int renderingTime() const
Returns the total time it took to finish the job (in milliseconds).
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:251
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning)
add a message to the instance (and create it if necessary)
QgsCoordinateTransformContext transformContext() const
Returns a copy of the project&#39;s coordinate transform context, which stores various information regard...
Definition: qgsproject.cpp:474
Enable drawing of labels on top of the map.
static QString worldFileContent(const QgsMapSettings &mapSettings)
Creates the content of a world file.
double maxRenderingTimeMs
Default maximum allowable render time, in ms.
void zoomLastStatusChanged(bool)
Emitted when zoom last status changed.
A graphics effect which can be applied to a widget to simulate various printing and color blindness m...
virtual void canvasPressEvent(QgsMapMouseEvent *e)
Mouse press event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:158
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
void setCache(QgsMapRendererCache *cache)
Assign a cache to be used for reading and storing rendered images of individual layers.
void magnificationChanged(double)
Emitted when the scale of the map changes.
QString what() const
Definition: qgsexception.h:48
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void updateScale()
Emits signal scaleChanged to update scale in main window.
QgsUnitTypes::DistanceUnit mapUnits() const
Get units of map&#39;s geographical coordinates - used for scale calculation.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
The QgsMapSettings class contains configuration for rendering of the map.
void resizeEvent(QResizeEvent *e) override
Overridden resize event.
Deprecated to be deleted, stuff from here should be moved elsewhere.
void enableMapTileRendering(bool flag)
sets map tile rendering flag
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:81
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:36
void setSnappingUtils(QgsSnappingUtils *utils)
Assign an instance of snapping utils to the map canvas.
virtual void keyReleaseEvent(QKeyEvent *e)
Key event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:178
void mapThemeChanged(const QString &theme)
Emitted when a map theme changes definition.
QgsRectangle boundingBoxOfSelected() const
Returns the bounding box of the selected features. If there is no selection, QgsRectangle(0,0,0,0) is returned.
QgsRectangle extent() const
Return geographical coordinates of the rectangle that should be rendered.
void setMapTool(QgsMapTool *mapTool, bool clean=false)
Sets the map tool currently being used on the canvas.
Map tool is an edit tool, which can only be used when layer is editable.
Definition: qgsmaptool.h:94
void setOutputSize(QSize size)
Set the size of the resulting map image.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QString id() const
Returns the layer&#39;s unique ID, which is used to access this layer from QgsProject.
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
void start() override
Start the rendering job and immediately return.
void saveAsImage(const QString &fileName, QPixmap *QPixmap=nullptr, const QString &="PNG")
Save the convtents of the map canvas to disk as an image.
QgsMapThemeCollection mapThemeCollection
Definition: qgsproject.h:90
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets global labeling engine settings in the internal map settings.
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
void rotationChanged(double)
Emitted when the rotation of the map changes.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
void setMagnificationFactor(double factor)
Set the magnification factor.
void zoomNextStatusChanged(bool)
Emitted when zoom next status changed.
bool isEmpty() const
Returns true if the rectangle is empty.
A circle is used to highlight points (○)
Definition: qgsrubberband.h:68
void flashFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids, const QColor &startColor=QColor(255, 0, 0, 255), const QColor &endColor=QColor(255, 0, 0, 0), int flashes=3, int duration=500)
Causes a set of features with matching ids from a vector layer to flash within the canvas...
void clearCache()
Make sure to remove any rendered images from cache (does nothing if cache is not enabled) ...
QgsMapCanvas(QWidget *parent=nullptr)
Constructor.
A class for drawing transient features (e.g.
Definition: qgsrubberband.h:37
double scale() const
Returns the calculated map scale.
Job implementation that renders all layers in parallel.
void selectionChanged(const QgsFeatureIds &selected, const QgsFeatureIds &deselected, const bool clearAndSelect)
This signal is emitted when selection was changed.
double width() const
Returns the width of the rectangle.
Definition: qgsrectangle.h:142
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:99
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setSegmentationTolerance(double tolerance)
Sets the segmentation tolerance applied when rendering curved geometries.
void setMapUpdateInterval(int timeMilliseconds)
Set how often map preview should be updated while it is being rendered (in milliseconds) ...
void keyReleased(QKeyEvent *e)
Emit key release event.
virtual void waitForFinished()=0
Block until the job has finished.
double mapUnitsPerPixel() const
Return the distance in geographical coordinates that equals to one pixel in the map.
void readProject(const QDomDocument &)
emitted when project is being read
Enable anti-aliasing for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:663
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Centers canvas extent to feature ids.
void mouseDoubleClickEvent(QMouseEvent *e) override
Overridden mouse double-click event.
This class wraps a request for features to a vector layer (or directly its vector data provider)...
void panToSelected(QgsVectorLayer *layer=nullptr)
Pan to the selected features of current (vector) layer keeping same extent.
bool isSpatial() const override
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
QgsRectangle layerExtentToOutputExtent(const QgsMapLayer *layer, QgsRectangle extent) const
transform bounding box from layer&#39;s CRS to output CRS
void setWheelFactor(double factor)
set wheel zoom factor (should be greater than 1)
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
void destinationCrsChanged()
Emitted when map CRS has changed.
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
bool isFrozen() const
Returns true if canvas is frozen.
void setCachingEnabled(bool enabled)
Set whether to cache images of rendered layers.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:97
Single scope for storing variables and functions for use within a QgsExpressionContext.
Contains information about the context in which a coordinate transform is executed.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:101
double mapUnitsPerPixel() const
Return current map units per pixel.
void setPreviewMode(QgsPreviewEffect::PreviewMode mode)
Sets a preview mode for the map canvas.
virtual void wheelEvent(QWheelEvent *e)
Mouse wheel event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:168
QHash< QgsMapLayer *, int > perLayerRenderingTime() const
Returns the render time (in ms) per layer.
void transformContextChanged()
Emitted when the canvas transform context is changed.
void setMode(PreviewMode mode)
Sets the mode for the preview effect, which controls how the effect modifies a widgets appearance...
void renderStarting()
Emitted when the canvas is about to be rendered.
const QgsMapToPixel & mapToPixel() const
void keyPressed(QKeyEvent *e)
Emit key press event.
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
void zoomOut()
Zoom out with fixed factor.
Enable drawing of vertex markers for layers in editing mode.
void waitWhileRendering()
Blocks until the rendering job has finished.
constexpr double CANVAS_MAGNIFICATION_MIN
Minimum magnification level allowed in map canvases.
Definition: qgsguiutils.h:61
void zoomToPreviousExtent()
Zoom to the previous extent (view)
bool isDrawing()
Find out whether rendering is in progress.
void zoomByFactor(double scaleFactor, const QgsPointXY *center=nullptr)
Zoom with the factor supplied.
bool addSourceDestinationDatumTransform(const QgsCoordinateReferenceSystem &sourceCrs, const QgsCoordinateReferenceSystem &destinationCrs, int sourceTransformId, int destinationTransformId)
Adds a new sourceTransform and destinationTransform to use when projecting coordinates from the the s...
double x
Definition: qgspointxy.h:47
virtual bool renderInPreview(const QgsDataProvider::PreviewContext &context)
Returns whether the layer must be rendered in preview jobs.
void zoomToSelected(QgsVectorLayer *layer=nullptr)
Zoom to the extent of the selected features of current (vector) layer.
A class to represent a vector.
Definition: qgsvector.h:27
PreviewMode mode() const
Returns the mode used for the preview effect.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const override
Query the layer for features specified in request.
void repaintRequested(bool deferredUpdate=false)
By emitting this signal the layer tells that either appearance or content have been changed and any v...
void setPreviewModeEnabled(bool previewEnabled)
Enables a preview mode for the map canvas.
virtual void start()=0
Start the rendering job and immediately return.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QPoint mouseLastXY()
returns last position of mouse cursor
double yMinimum() const
Returns the y minimum value (bottom side of rectangle).
Definition: qgsrectangle.h:130
double magnificationFactor() const
Returns the magnification factor.
void setRotation(double rotation)
Sets the rotation of the resulting map image, in degrees clockwise.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QMap< QString, QString > layerStyleOverrides() const
Returns the stored overrides of styles for layers.
void mouseMoveEvent(QMouseEvent *e) override
Overridden mouse move event.
void keyReleaseEvent(QKeyEvent *e) override
Overridden key release event.
void selectionChanged(QgsMapLayer *layer)
Emitted when selection in any layer gets changed.
int availableTransformationCount()
Returns the number of possible datum transformation for currently selected source and destination CRS...
virtual void keyPressEvent(QKeyEvent *e)
Key event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:173
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:43
void flashGeometries(const QList< QgsGeometry > &geometries, const QgsCoordinateReferenceSystem &crs=QgsCoordinateReferenceSystem(), const QColor &startColor=QColor(255, 0, 0, 255), const QColor &endColor=QColor(255, 0, 0, 0), int flashes=3, int duration=500)
Causes a set of geometries to flash within the canvas.
double scale() const
Returns the last reported scale of the canvas.
double xMaximum() const
Returns the x maximum value (right side of rectangle).
Definition: qgsrectangle.h:115
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void combineExtentWith(const QgsRectangle &rect)
Expand the rectangle so that covers both the original rectangle and the given rectangle.
QColor canvasColor() const
Read property of QColor bgColor.
void clear()
Invalidates the cache contents, clearing all cached images.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:137
Abstract base class for all map tools.
Definition: qgsmaptool.h:63
void selectionChangedSlot()
Receives signal about selection change, and pass it on with layer info.
Draw map such that there are no problems between adjacent tiles.
Job implementation that renders everything sequentially in one thread.
Render is a &#39;canvas preview&#39; render, and shortcuts should be taken to ensure fast rendering...
QgsUnitTypes::DistanceUnit mapUnits() const
Convience function for returning the current canvas map units.
void setBackgroundColor(const QColor &color)
Set the background color of the map.
void setLabelingEngineSettings(const QgsLabelingEngineSettings &settings)
Sets global configuration of the labeling engine.
void mouseReleaseEvent(QMouseEvent *e) override
Overridden mouse release event.
void writeProject(QDomDocument &)
emitted when project is being written
QgsPointXY toMapPoint(double x, double y) const
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:224
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
QString theme() const
Returns the map&#39;s theme shown in the canvas, if set.
Definition: qgsmapcanvas.h:435
QgsPointXY center() const
Get map center, in geographical coordinates.
virtual bool gestureEvent(QGestureEvent *e)
gesture event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:183
void setSelectionColor(const QColor &color)
Set color that is used for drawing of selected vector features.
void layerStyleOverridesChanged()
Emitted when the configuration of overridden layer styles changes.
virtual void canvasDoubleClickEvent(QgsMapMouseEvent *e)
Mouse double-click event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:153
void dragEnterEvent(QDragEnterEvent *e) override
Overridden drag enter event.
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:104
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
void writeProject(QDomDocument &)
called to write map canvas settings to project
void panAction(QMouseEvent *event)
Called when mouse is moving and pan is activated.
void setLayers(const QList< QgsMapLayer *> &layers)
Sets the list of layers that should be shown in the canvas.
QgsRectangle fullExtent() const
returns current extent of layer set
Intermediate base class adding functionality that allows client to query the rendered image...
Stores global configuration for labeling engine.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:383
void zoomToFullExtent()
Zoom to the full extent of all layers.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
QgsRectangle fullExtent() const
Returns the combined extent for all layers on the map canvas.
This class has all the configuration of snapping and can return answers to snapping queries...
const QgsLabelingResults * labelingResults() const
Get access to the labeling results (may be null)
void setTransformContext(const QgsCoordinateTransformContext &context)
Sets the project&#39;s coordinate transform context, which stores various information regarding which dat...
Definition: qgsproject.cpp:479
bool isNull() const
Test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void setMapSettingsFlags(QgsMapSettings::Flags flags)
Resets the flags for the canvas&#39; map settings.
QgsVectorDataProvider * dataProvider() override
Returns the layer&#39;s data provider.
void refreshAllLayers()
Reload all layers, clear the cache and refresh the canvas.
void zoomScale(double scale)
Zooms the canvas to a specific scale.
Class for doing transforms between two map coordinate systems.
void setExtent(const QgsRectangle &r, bool magnified=false)
Set the extent of the map canvas.
double xMinimum() const
Returns the x minimum value (left side of rectangle).
Definition: qgsrectangle.h:120
void setLayers(const QList< QgsMapLayer *> &layers)
Set list of layers for map rendering.
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
void scaleChanged(double)
Emitted when the scale of the map changes.
void setPathResolver(const QgsPathResolver &resolver)
Sets the path resolver for conversion between relative and absolute paths during rendering operations...
void setSegmentationToleranceType(QgsAbstractGeometry::SegmentationToleranceType type)
Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
virtual void cancelWithoutBlocking()=0
Triggers cancelation of the rendering job without blocking.
double yMaximum() const
Returns the y maximum value (top side of rectangle).
Definition: qgsrectangle.h:125
void setSelectionColor(const QColor &color)
Set color of selected vector features.
void paintEvent(QPaintEvent *e) override
Overridden paint event.
void layerStateChange()
This slot is connected to the visibility change of one or more layers.
double lastRenderingTimeMs
Previous rendering time for the layer, in ms.
Enable vector simplification and other rendering optimizations.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
void freeze(bool frozen=true)
Freeze/thaw the map canvas.
void setScaleLocked(bool isLocked)
Lock the scale, so zooming can be performed using magnication.
Class that stores computed placement from labeling engine.
This class is responsible for keeping cache of rendered images resulting from a map rendering job...
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
void transformContextChanged()
Emitted when the project transformContext() is changed.
Custom exception class for Coordinate Reference System related exceptions.
Definition: qgsexception.h:65
void setTheme(const QString &theme)
Sets a map theme to show in the canvas.
QColor selectionColor() const
Get color that is used for drawing of selected vector features.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:170
QList< int > QgsAttributeList
Definition: qgsfield.h:27
void readXml(QDomNode &node)
bool nextFeature(QgsFeature &f)
QPoint rubberStartPoint
Beginning point of a rubber band.
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
QgsSnappingUtils * snappingUtils() const
Return snapping utility class that is associated with map canvas.
virtual QgsLabelingResults * takeLabelingResults()=0
Get pointer to internal labeling engine (in order to get access to the results).
void xyCoordinates(const QgsPointXY &p)
Emits current mouse position.
void autoRefreshIntervalChanged(int interval)
Emitted when the auto refresh interval changes.
void writeXml(QDomNode &node, QDomDocument &doc)
void zoomIn()
Zoom in with fixed factor.
Stores settings related to the context in which a preview job runs.
void waitForFinished() override
Block until the job has finished.
Represents a vector layer which manages a vector based data sets.
virtual void updatePosition()
called on changed extent or resize event to update position of the item
bool isParallelRenderingEnabled() const
Check whether the layers are rendered in parallel or sequentially.
const QgsMapSettings & mapSettings() const
Return map settings with which this job was started.
void mapToolSet(QgsMapTool *newTool, QgsMapTool *oldTool)
Emit map tool changed with the old tool.
CanvasProperties()=default
Constructor for CanvasProperties.
An interactive map canvas item which displays a QgsAnnotation.
void themeChanged(const QString &theme)
Emitted when the canvas has been assigned a different map theme.
void extentsChanged()
Emitted when the extents of the map change.
virtual void clean()
convenient method to clean members
Definition: qgsmaptool.cpp:107
QSize outputSize() const
Return the size of the resulting map image.
void ellipsoidChanged(const QString &ellipsoid)
Emitted when the project ellipsoid is changed.
QgsPointXY toMapCoordinates(int x, int y) const
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
QString authid() const
Returns the authority identifier for the CRS.
virtual bool isActive() const =0
Tell whether the rendering job is currently running in background.
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:89
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:149
void setMagnificationFactor(double factor)
Sets the factor of magnification to apply to the map canvas.
const QgsLabelingEngineSettings & labelingEngineSettings() const
Returns global configuration of the labeling engine.
void panActionEnd(QPoint releasePoint)
Ends pan action and redraws the canvas.
bool previewModeEnabled() const
Returns whether a preview mode is enabled for the map canvas.
void layersChanged()
Emitted when a new set of layers has been received.
void messageEmitted(const QString &title, const QString &message, Qgis::MessageLevel=Qgis::Info)
emit a message (usually to be displayed in a message bar)
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
virtual bool usedCachedLabels() const =0
Returns true if the render job was able to use a cached labeling solution.
~QgsMapCanvas() override
virtual void canvasReleaseEvent(QgsMapMouseEvent *e)
Mouse release event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:163