QGIS API Documentation  2.99.0-Master (5dc91b4)
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 = QgsAbstractGeometry::SegmentationToleranceType( settings.value( QStringLiteral( "qgis/segmentationToleranceType" ), 0 ).toInt() );
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 
507  if ( !mTheme.isEmpty() )
508  {
509  // IMPORTANT: we MUST set the layer style overrides here! (At the time of writing this
510  // comment) retrieving layer styles from the theme collection gives an XML snapshot of the
511  // current state of the style. If we had stored the style overrides earlier (such as in
512  // mapThemeChanged slot) then this xml could be out of date...
513  // TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
514  // just return the style name, we can instead set the overrides in mapThemeChanged and not here
515  mSettings.setLayerStyleOverrides( QgsProject::instance()->mapThemeCollection()->mapThemeStyleOverrides( mTheme ) );
516  }
517 
518  // create the renderer job
519  Q_ASSERT( !mJob );
520  mJobCanceled = false;
521  if ( mUseParallelRendering )
522  mJob = new QgsMapRendererParallelJob( mSettings );
523  else
524  mJob = new QgsMapRendererSequentialJob( mSettings );
525  connect( mJob, &QgsMapRendererJob::finished, this, &QgsMapCanvas::rendererJobFinished );
526  mJob->setCache( mCache );
527 
528  mJob->start();
529 
530  // from now on we can accept refresh requests again
531  // this must be reset only after the job has been started, because
532  // some providers (yes, it's you WCS and AMS!) during preparation
533  // do network requests and start an internal event loop, which may
534  // end up calling refresh() and would schedule another refresh,
535  // deleting the one we have just started.
536  mRefreshScheduled = false;
537 
538  mMapUpdateTimer.start();
539 
540  emit renderStarting();
541 }
542 
543 void QgsMapCanvas::mapThemeChanged( const QString &theme )
544 {
545  if ( theme == mTheme )
546  {
547  // set the canvas layers to match the new layers contained in the map theme
548  // NOTE: we do this when the theme layers change and not when we are refreshing the map
549  // as setLayers() sets up necessary connections to handle changes to the layers
550  setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
551  // IMPORTANT: we don't set the layer style overrides here! (At the time of writing this
552  // comment) retrieving layer styles from the theme collection gives an XML snapshot of the
553  // current state of the style. If changes were made to the style then this xml
554  // snapshot goes out of sync...
555  // TODO: if in future QgsMapThemeCollection::mapThemeStyleOverrides is changed to
556  // just return the style name, we can instead set the overrides here and not in refreshMap()
557 
558  clearCache();
559  refresh();
560  }
561 }
562 
563 
564 void QgsMapCanvas::rendererJobFinished()
565 {
566  QgsDebugMsg( QString( "CANVAS finish! %1" ).arg( !mJobCanceled ) );
567 
568  mMapUpdateTimer.stop();
569 
570  // TODO: would be better to show the errors in message bar
571  Q_FOREACH ( const QgsMapRendererJob::Error &error, mJob->errors() )
572  {
573  QgsMessageLog::logMessage( error.layerID + " :: " + error.message, tr( "Rendering" ) );
574  }
575 
576  if ( !mJobCanceled )
577  {
578  // take labeling results before emitting renderComplete, so labeling map tools
579  // connected to signal work with correct results
580  if ( !mJob->usedCachedLabels() )
581  {
582  delete mLabelingResults;
583  mLabelingResults = mJob->takeLabelingResults();
584  }
585 
586  QImage img = mJob->renderedImage();
587 
588  // emit renderComplete to get our decorations drawn
589  QPainter p( &img );
590  emit renderComplete( &p );
591 
592  QgsSettings settings;
593  if ( settings.value( QStringLiteral( "Map/logCanvasRefreshEvent" ), false ).toBool() )
594  {
595  QString logMsg = tr( "Canvas refresh: %1 ms" ).arg( mJob->renderingTime() );
596  QgsMessageLog::logMessage( logMsg, tr( "Rendering" ) );
597  }
598 
599  if ( mDrawRenderingStats )
600  {
601  int w = img.width(), h = img.height();
602  QFont fnt = p.font();
603  fnt.setBold( true );
604  p.setFont( fnt );
605  int lh = p.fontMetrics().height() * 2;
606  QRect r( 0, h - lh, w, lh );
607  p.setPen( Qt::NoPen );
608  p.setBrush( QColor( 0, 0, 0, 110 ) );
609  p.drawRect( r );
610  p.setPen( Qt::white );
611  QString msg = QStringLiteral( "%1 :: %2 ms" ).arg( mUseParallelRendering ? "PARALLEL" : "SEQUENTIAL" ).arg( mJob->renderingTime() );
612  p.drawText( r, msg, QTextOption( Qt::AlignCenter ) );
613  }
614 
615  p.end();
616 
617  mMap->setContent( img, imageRect( img, mSettings ) );
618 
619  mLastLayerRenderTime.clear();
620  const auto times = mJob->perLayerRenderingTime();
621  for ( auto it = times.constBegin(); it != times.constEnd(); ++it )
622  {
623  mLastLayerRenderTime.insert( it.key()->id(), it.value() );
624  }
625  if ( mUsePreviewJobs )
626  startPreviewJobs();
627  }
628 
629  // now we are in a slot called from mJob - do not delete it immediately
630  // so the class is still valid when the execution returns to the class
631  mJob->deleteLater();
632  mJob = nullptr;
633 
634  emit mapCanvasRefreshed();
635 }
636 
637 void QgsMapCanvas::previewJobFinished()
638 {
639  QgsMapRendererQImageJob *job = qobject_cast<QgsMapRendererQImageJob *>( sender() );
640  Q_ASSERT( job );
641 
642  if ( mMap )
643  {
644  mMap->addPreviewImage( job->renderedImage(), job->mapSettings().extent() );
645  mPreviewJobs.removeAll( job );
646 
647  int number = job->property( "number" ).toInt();
648  if ( number < 8 )
649  {
650  startPreviewJob( number + 1 );
651  }
652 
653  delete job;
654  }
655 }
656 
657 QgsRectangle QgsMapCanvas::imageRect( const QImage &img, const QgsMapSettings &mapSettings )
658 {
659  // This is a hack to pass QgsMapCanvasItem::setRect what it
660  // expects (encoding of position and size of the item)
661  const QgsMapToPixel &m2p = mapSettings.mapToPixel();
662  QgsPointXY topLeft = m2p.toMapPoint( 0, 0 );
663  double res = m2p.mapUnitsPerPixel();
664  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + img.width()*res, topLeft.y() - img.height()*res );
665  return rect;
666 }
667 
669 {
670  return mUsePreviewJobs;
671 }
672 
674 {
675  mUsePreviewJobs = enabled;
676 }
677 
678 void QgsMapCanvas::mapUpdateTimeout()
679 {
680  if ( mJob )
681  {
682  const QImage &img = mJob->renderedImage();
683  mMap->setContent( img, imageRect( img, mSettings ) );
684  }
685 }
686 
688 {
689  if ( mJob )
690  {
691  QgsDebugMsg( "CANVAS stop rendering!" );
692  mJobCanceled = true;
693  disconnect( mJob, &QgsMapRendererJob::finished, this, &QgsMapCanvas::rendererJobFinished );
694  connect( mJob, &QgsMapRendererQImageJob::finished, mJob, &QgsMapRendererQImageJob::deleteLater );
695  mJob->cancelWithoutBlocking();
696  mJob = nullptr;
697  }
698  stopPreviewJobs();
699 }
700 
701 //the format defaults to "PNG" if not specified
702 void QgsMapCanvas::saveAsImage( const QString &fileName, QPixmap *theQPixmap, const QString &format )
703 {
704  QPainter painter;
705  QImage image;
706 
707  //
708  //check if the optional QPaintDevice was supplied
709  //
710  if ( theQPixmap )
711  {
712  image = theQPixmap->toImage();
713  painter.begin( &image );
714 
715  // render
716  QgsMapRendererCustomPainterJob job( mSettings, &painter );
717  job.start();
718  job.waitForFinished();
719  emit renderComplete( &painter );
720  }
721  else //use the map view
722  {
723  image = mMap->contentImage().copy();
724  painter.begin( &image );
725  }
726 
727  // draw annotations
728  QStyleOptionGraphicsItem option;
729  option.initFrom( this );
730  QGraphicsItem *item = nullptr;
731  QListIterator<QGraphicsItem *> i( items() );
732  i.toBack();
733  while ( i.hasPrevious() )
734  {
735  item = i.previous();
736 
737  if ( !item || dynamic_cast< QgsMapCanvasAnnotationItem * >( item ) )
738  {
739  continue;
740  }
741 
742  painter.save();
743 
744  QPointF itemScenePos = item->scenePos();
745  painter.translate( itemScenePos.x(), itemScenePos.y() );
746 
747  item->paint( &painter, &option );
748 
749  painter.restore();
750  }
751 
752  painter.end();
753  image.save( fileName, format.toLocal8Bit().data() );
754 
755  QFileInfo myInfo = QFileInfo( fileName );
756 
757  // build the world file name
758  QString outputSuffix = myInfo.suffix();
759  QString myWorldFileName = myInfo.absolutePath() + '/' + myInfo.baseName() + '.'
760  + outputSuffix.at( 0 ) + outputSuffix.at( myInfo.suffix().size() - 1 ) + 'w';
761  QFile myWorldFile( myWorldFileName );
762  if ( !myWorldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) //don't use QIODevice::Text
763  {
764  return;
765  }
766  QTextStream myStream( &myWorldFile );
768 } // saveAsImage
769 
770 
771 
773 {
774  return mapSettings().visibleExtent();
775 } // extent
776 
778 {
779  return mapSettings().fullExtent();
780 } // extent
781 
782 
783 void QgsMapCanvas::setExtent( const QgsRectangle &r, bool magnified )
784 {
785  QgsRectangle current = extent();
786 
787  if ( ( r == current ) && magnified )
788  return;
789 
790  if ( r.isEmpty() )
791  {
792  if ( !mSettings.hasValidSettings() )
793  {
794  // we can't even just move the map center
795  QgsDebugMsg( "Empty extent - ignoring" );
796  return;
797  }
798 
799  // ### QGIS 3: do not allow empty extent - require users to call setCenter() explicitly
800  QgsDebugMsg( "Empty extent - keeping old scale with new center!" );
801  setCenter( r.center() );
802  }
803  else
804  {
805  mSettings.setExtent( r, magnified );
806  }
807  emit extentsChanged();
808  updateScale();
809  if ( mLastExtent.size() > 20 )
810  mLastExtent.removeAt( 0 );
811 
812  //clear all extent items after current index
813  for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
814  {
815  mLastExtent.removeAt( i );
816  }
817 
818  mLastExtent.append( extent() );
819 
820  // adjust history to no more than 20
821  if ( mLastExtent.size() > 20 )
822  {
823  mLastExtent.removeAt( 0 );
824  }
825 
826  // the last item is the current extent
827  mLastExtentIndex = mLastExtent.size() - 1;
828 
829  // update controls' enabled state
830  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
831  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
832 } // setExtent
833 
835 {
837  double x = center.x();
838  double y = center.y();
839  setExtent(
840  QgsRectangle(
841  x - r.width() / 2.0, y - r.height() / 2.0,
842  x + r.width() / 2.0, y + r.height() / 2.0
843  ),
844  true
845  );
846 } // setCenter
847 
849 {
851  return r.center();
852 }
853 
854 
856 {
857  return mapSettings().rotation();
858 } // rotation
859 
860 void QgsMapCanvas::setRotation( double degrees )
861 {
862  double current = rotation();
863 
864  if ( degrees == current )
865  return;
866 
867  mSettings.setRotation( degrees );
868  emit rotationChanged( degrees );
869  emit extentsChanged(); // visible extent changes with rotation
870 } // setRotation
871 
872 
874 {
875  emit scaleChanged( mapSettings().scale() );
876 }
877 
878 
880 {
882  // If the full extent is an empty set, don't do the zoom
883  if ( !extent.isEmpty() )
884  {
885  // Add a 5% margin around the full extent
886  extent.scale( 1.05 );
887  setExtent( extent );
888  }
889  refresh();
890 
891 } // zoomToFullExtent
892 
893 
894 
896 {
897  if ( mLastExtentIndex > 0 )
898  {
899  mLastExtentIndex--;
900  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
901  emit extentsChanged();
902  updateScale();
903  refresh();
904  // update controls' enabled state
905  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
906  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
907  }
908 
909 } // zoomToPreviousExtent
910 
912 {
913  if ( mLastExtentIndex < mLastExtent.size() - 1 )
914  {
915  mLastExtentIndex++;
916  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
917  emit extentsChanged();
918  updateScale();
919  refresh();
920  // update controls' enabled state
921  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
922  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
923  }
924 }// zoomToNextExtent
925 
927 {
928  mLastExtent.clear(); // clear the zoom history list
929  mLastExtent.append( extent() ) ; // set the current extent in the list
930  mLastExtentIndex = mLastExtent.size() - 1;
931  // update controls' enabled state
932  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
933  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
934 }// clearExtentHistory
935 
937 {
938  if ( !layer )
939  {
940  // use current layer by default
941  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
942  }
943 
944  if ( !layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0 )
945  return;
946 
947  QgsRectangle rect = layer->boundingBoxOfSelected();
948  if ( rect.isNull() )
949  {
950  emit messageEmitted( tr( "Cannot zoom to selected feature(s)" ), tr( "No extent could be determined." ), QgsMessageBar::WARNING );
951  return;
952  }
953 
954  rect = mapSettings().layerExtentToOutputExtent( layer, rect );
955  zoomToFeatureExtent( rect );
956 } // zoomToSelected
957 
959 {
960  // no selected features, only one selected point feature
961  //or two point features with the same x- or y-coordinates
962  if ( rect.isEmpty() )
963  {
964  // zoom in
965  QgsPointXY c = rect.center();
966  rect = extent();
967  rect.scale( 1.0, &c );
968  }
969  //zoom to an area
970  else
971  {
972  // Expand rect to give a bit of space around the selected
973  // objects so as to keep them clear of the map boundaries
974  // The same 5% should apply to all margins.
975  rect.scale( 1.05 );
976  }
977 
978  setExtent( rect );
979  refresh();
980 }
981 
983 {
984  if ( !layer )
985  {
986  return;
987  }
988 
989  QgsRectangle bbox;
990  QString errorMsg;
991  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
992  {
993  zoomToFeatureExtent( bbox );
994  }
995  else
996  {
997  emit messageEmitted( tr( "Zoom to feature id failed" ), errorMsg, QgsMessageBar::WARNING );
998  }
999 
1000 }
1001 
1003 {
1004  if ( !layer )
1005  {
1006  return;
1007  }
1008 
1009  QgsRectangle bbox;
1010  QString errorMsg;
1011  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
1012  {
1013  setCenter( bbox.center() );
1014  refresh();
1015  }
1016  else
1017  {
1018  emit messageEmitted( tr( "Pan to feature id failed" ), errorMsg, QgsMessageBar::WARNING );
1019  }
1020 }
1021 
1022 bool QgsMapCanvas::boundingBoxOfFeatureIds( const QgsFeatureIds &ids, QgsVectorLayer *layer, QgsRectangle &bbox, QString &errorMsg ) const
1023 {
1024  QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFids( ids ).setSubsetOfAttributes( QgsAttributeList() ) );
1025  bbox.setMinimal();
1026  QgsFeature fet;
1027  int featureCount = 0;
1028  errorMsg.clear();
1029 
1030  while ( it.nextFeature( fet ) )
1031  {
1032  QgsGeometry geom = fet.geometry();
1033  if ( geom.isNull() )
1034  {
1035  errorMsg = tr( "Feature does not have a geometry" );
1036  }
1037  else if ( geom.constGet()->isEmpty() )
1038  {
1039  errorMsg = tr( "Feature geometry is empty" );
1040  }
1041  if ( !errorMsg.isEmpty() )
1042  {
1043  return false;
1044  }
1046  bbox.combineExtentWith( r );
1047  featureCount++;
1048  }
1049 
1050  if ( featureCount != ids.count() )
1051  {
1052  errorMsg = tr( "Feature not found" );
1053  return false;
1054  }
1055 
1056  return true;
1057 }
1058 
1060 {
1061  if ( !layer )
1062  {
1063  // use current layer by default
1064  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1065  }
1066 
1067  if ( !layer || !layer->isSpatial() || layer->selectedFeatureCount() == 0 )
1068  return;
1069 
1070  QgsRectangle rect = layer->boundingBoxOfSelected();
1071  if ( rect.isNull() )
1072  {
1073  emit messageEmitted( tr( "Cannot pan to selected feature(s)" ), tr( "No extent could be determined." ), QgsMessageBar::WARNING );
1074  return;
1075  }
1076 
1077  rect = mapSettings().layerExtentToOutputExtent( layer, rect );
1078  setCenter( rect.center() );
1079  refresh();
1080 }
1081 
1083  const QColor &color1, const QColor &color2,
1084  int flashes, int duration )
1085 {
1086  if ( !layer )
1087  {
1088  return;
1089  }
1090 
1091  QList< QgsGeometry > geoms;
1092 
1093  QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFids( ids ).setSubsetOfAttributes( QgsAttributeList() ) );
1094  QgsFeature fet;
1095  while ( it.nextFeature( fet ) )
1096  {
1097  if ( !fet.hasGeometry() )
1098  continue;
1099  geoms << fet.geometry();
1100  }
1101 
1102  flashGeometries( geoms, layer->crs(), color1, color2, flashes, duration );
1103 }
1104 
1105 void QgsMapCanvas::flashGeometries( const QList<QgsGeometry> &geometries, const QgsCoordinateReferenceSystem &crs, const QColor &color1, const QColor &color2, int flashes, int duration )
1106 {
1107  if ( geometries.isEmpty() )
1108  return;
1109 
1110  QgsWkbTypes::GeometryType geomType = QgsWkbTypes::geometryType( geometries.at( 0 ).wkbType() );
1111  QgsRubberBand *rb = new QgsRubberBand( this, geomType );
1112  for ( const QgsGeometry &geom : geometries )
1113  rb->addGeometry( geom, crs );
1114 
1115  if ( geomType == QgsWkbTypes::LineGeometry || geomType == QgsWkbTypes::PointGeometry )
1116  {
1117  rb->setWidth( 2 );
1118  rb->setSecondaryStrokeColor( QColor( 255, 255, 255 ) );
1119  }
1120  if ( geomType == QgsWkbTypes::PointGeometry )
1121  rb->setIcon( QgsRubberBand::ICON_CIRCLE );
1122 
1123  QColor startColor = color1;
1124  if ( !startColor.isValid() )
1125  {
1126  if ( geomType == QgsWkbTypes::PolygonGeometry )
1127  {
1128  startColor = rb->fillColor();
1129  }
1130  else
1131  {
1132  startColor = rb->strokeColor();
1133  }
1134  startColor.setAlpha( 255 );
1135  }
1136  QColor endColor = color2;
1137  if ( !endColor.isValid() )
1138  {
1139  endColor = startColor;
1140  endColor.setAlpha( 0 );
1141  }
1142 
1143 
1144  QVariantAnimation *animation = new QVariantAnimation( this );
1145  connect( animation, &QVariantAnimation::finished, this, [animation, rb]
1146  {
1147  animation->deleteLater();
1148  delete rb;
1149  } );
1150  connect( animation, &QPropertyAnimation::valueChanged, this, [rb, geomType]( const QVariant & value )
1151  {
1152  QColor c = value.value<QColor>();
1153  if ( geomType == QgsWkbTypes::PolygonGeometry )
1154  {
1155  rb->setFillColor( c );
1156  }
1157  else
1158  {
1159  rb->setStrokeColor( c );
1160  QColor c = rb->secondaryStrokeColor();
1161  c.setAlpha( c.alpha() );
1162  rb->setSecondaryStrokeColor( c );
1163  }
1164  rb->update();
1165  } );
1166 
1167  animation->setDuration( duration * flashes );
1168  animation->setStartValue( endColor );
1169  double midStep = 0.2 / flashes;
1170  for ( int i = 0; i < flashes; ++i )
1171  {
1172  double start = static_cast< double >( i ) / flashes;
1173  animation->setKeyValueAt( start + midStep, startColor );
1174  double end = static_cast< double >( i + 1 ) / flashes;
1175  if ( !qgsDoubleNear( end, 1.0 ) )
1176  animation->setKeyValueAt( end, endColor );
1177  }
1178  animation->setEndValue( endColor );
1179  animation->start();
1180 }
1181 
1182 void QgsMapCanvas::keyPressEvent( QKeyEvent *e )
1183 {
1184  if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
1185  {
1186  emit keyPressed( e );
1187  return;
1188  }
1189 
1190  if ( ! mCanvasProperties->mouseButtonDown )
1191  {
1192  // Don't want to interfer with mouse events
1193 
1194  QgsRectangle currentExtent = mapSettings().visibleExtent();
1195  double dx = std::fabs( currentExtent.width() / 4 );
1196  double dy = std::fabs( currentExtent.height() / 4 );
1197 
1198  switch ( e->key() )
1199  {
1200  case Qt::Key_Left:
1201  QgsDebugMsg( "Pan left" );
1202  setCenter( center() - QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1203  refresh();
1204  break;
1205 
1206  case Qt::Key_Right:
1207  QgsDebugMsg( "Pan right" );
1208  setCenter( center() + QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1209  refresh();
1210  break;
1211 
1212  case Qt::Key_Up:
1213  QgsDebugMsg( "Pan up" );
1214  setCenter( center() + QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1215  refresh();
1216  break;
1217 
1218  case Qt::Key_Down:
1219  QgsDebugMsg( "Pan down" );
1220  setCenter( center() - QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1221  refresh();
1222  break;
1223 
1224 
1225 
1226  case Qt::Key_Space:
1227  QgsDebugMsg( "Pressing pan selector" );
1228 
1229  //mCanvasProperties->dragging = true;
1230  if ( ! e->isAutoRepeat() )
1231  {
1232  QApplication::setOverrideCursor( Qt::ClosedHandCursor );
1233  mCanvasProperties->panSelectorDown = true;
1234  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1235  }
1236  break;
1237 
1238  case Qt::Key_PageUp:
1239  QgsDebugMsg( "Zoom in" );
1240  zoomIn();
1241  break;
1242 
1243  case Qt::Key_PageDown:
1244  QgsDebugMsg( "Zoom out" );
1245  zoomOut();
1246  break;
1247 
1248 #if 0
1249  case Qt::Key_P:
1250  mUseParallelRendering = !mUseParallelRendering;
1251  refresh();
1252  break;
1253 
1254  case Qt::Key_S:
1255  mDrawRenderingStats = !mDrawRenderingStats;
1256  refresh();
1257  break;
1258 #endif
1259 
1260  default:
1261  // Pass it on
1262  if ( mMapTool )
1263  {
1264  mMapTool->keyPressEvent( e );
1265  }
1266  else e->ignore();
1267 
1268  QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
1269  }
1270  }
1271 
1272  emit keyPressed( e );
1273 
1274 } //keyPressEvent()
1275 
1276 void QgsMapCanvas::keyReleaseEvent( QKeyEvent *e )
1277 {
1278  QgsDebugMsg( "keyRelease event" );
1279 
1280  switch ( e->key() )
1281  {
1282  case Qt::Key_Space:
1283  if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
1284  {
1285  QgsDebugMsg( "Releasing pan selector" );
1286  QApplication::restoreOverrideCursor();
1287  mCanvasProperties->panSelectorDown = false;
1288  panActionEnd( mCanvasProperties->mouseLastXY );
1289  }
1290  break;
1291 
1292  default:
1293  // Pass it on
1294  if ( mMapTool )
1295  {
1296  mMapTool->keyReleaseEvent( e );
1297  }
1298  else e->ignore();
1299 
1300  QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
1301  }
1302 
1303  emit keyReleased( e );
1304 
1305 } //keyReleaseEvent()
1306 
1307 
1309 {
1310  // call handler of current map tool
1311  if ( mMapTool )
1312  {
1313  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1314  mMapTool->canvasDoubleClickEvent( me.get() );
1315  }
1316 }// mouseDoubleClickEvent
1317 
1318 
1319 void QgsMapCanvas::beginZoomRect( QPoint pos )
1320 {
1321  mZoomRect.setRect( 0, 0, 0, 0 );
1322  QApplication::setOverrideCursor( mZoomCursor );
1323  mZoomDragging = true;
1324  mZoomRubberBand.reset( new QgsRubberBand( this, QgsWkbTypes::PolygonGeometry ) );
1325  QColor color( Qt::blue );
1326  color.setAlpha( 63 );
1327  mZoomRubberBand->setColor( color );
1328  mZoomRect.setTopLeft( pos );
1329 }
1330 
1331 void QgsMapCanvas::endZoomRect( QPoint pos )
1332 {
1333  mZoomDragging = false;
1334  mZoomRubberBand.reset( nullptr );
1335  QApplication::restoreOverrideCursor();
1336 
1337  // store the rectangle
1338  mZoomRect.setRight( pos.x() );
1339  mZoomRect.setBottom( pos.y() );
1340 
1341  if ( mZoomRect.width() < 5 && mZoomRect.height() < 5 )
1342  {
1343  //probably a mistake - would result in huge zoom!
1344  return;
1345  }
1346 
1347  //account for bottom right -> top left dragging
1348  mZoomRect = mZoomRect.normalized();
1349 
1350  // set center and zoom
1351  const QSize &zoomRectSize = mZoomRect.size();
1352  const QSize &canvasSize = mSettings.outputSize();
1353  double sfx = ( double )zoomRectSize.width() / canvasSize.width();
1354  double sfy = ( double )zoomRectSize.height() / canvasSize.height();
1355  double sf = std::max( sfx, sfy );
1356 
1357  QgsPointXY c = mSettings.mapToPixel().toMapCoordinates( mZoomRect.center() );
1358 
1359  zoomByFactor( sf, &c );
1360  refresh();
1361 }
1362 
1363 void QgsMapCanvas::mousePressEvent( QMouseEvent *e )
1364 {
1365  //use middle mouse button for panning, map tools won't receive any events in that case
1366  if ( e->button() == Qt::MidButton )
1367  {
1368  mCanvasProperties->panSelectorDown = true;
1369  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1370  }
1371  else
1372  {
1373  // call handler of current map tool
1374  if ( mMapTool )
1375  {
1376  if ( mMapTool->flags() & QgsMapTool::AllowZoomRect && e->button() == Qt::LeftButton
1377  && e->modifiers() & Qt::ShiftModifier )
1378  {
1379  beginZoomRect( e->pos() );
1380  return;
1381  }
1382  else
1383  {
1384  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1385  mMapTool->canvasPressEvent( me.get() );
1386  }
1387  }
1388  }
1389 
1390  if ( mCanvasProperties->panSelectorDown )
1391  {
1392  return;
1393  }
1394 
1395  mCanvasProperties->mouseButtonDown = true;
1396  mCanvasProperties->rubberStartPoint = e->pos();
1397 
1398 } // mousePressEvent
1399 
1400 
1401 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent *e )
1402 {
1403  //use middle mouse button for panning, map tools won't receive any events in that case
1404  if ( e->button() == Qt::MidButton )
1405  {
1406  mCanvasProperties->panSelectorDown = false;
1407  panActionEnd( mCanvasProperties->mouseLastXY );
1408  }
1409  else if ( e->button() == Qt::BackButton )
1410  {
1412  return;
1413  }
1414  else if ( e->button() == Qt::ForwardButton )
1415  {
1416  zoomToNextExtent();
1417  return;
1418  }
1419  else
1420  {
1421  if ( mZoomDragging && e->button() == Qt::LeftButton )
1422  {
1423  endZoomRect( e->pos() );
1424  return;
1425  }
1426 
1427  // call handler of current map tool
1428  if ( mMapTool )
1429  {
1430  // right button was pressed in zoom tool? return to previous non zoom tool
1431  if ( e->button() == Qt::RightButton && mMapTool->flags() & QgsMapTool::Transient )
1432  {
1433  QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
1434  QString( mLastNonZoomMapTool ? "not null." : "null." ) );
1435 
1436  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1437 
1438  // change to older non-zoom tool
1439  if ( mLastNonZoomMapTool
1440  && ( !( mLastNonZoomMapTool->flags() & QgsMapTool::EditTool )
1441  || ( vlayer && vlayer->isEditable() ) ) )
1442  {
1443  QgsMapTool *t = mLastNonZoomMapTool;
1444  mLastNonZoomMapTool = nullptr;
1445  setMapTool( t );
1446  }
1447  return;
1448  }
1449  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1450  mMapTool->canvasReleaseEvent( me.get() );
1451  }
1452  }
1453 
1454 
1455  mCanvasProperties->mouseButtonDown = false;
1456 
1457  if ( mCanvasProperties->panSelectorDown )
1458  return;
1459 
1460 } // mouseReleaseEvent
1461 
1462 void QgsMapCanvas::resizeEvent( QResizeEvent *e )
1463 {
1464  QGraphicsView::resizeEvent( e );
1465  mResizeTimer->start( 500 );
1466 
1467  QSize lastSize = viewport()->size();
1468 
1469  mSettings.setOutputSize( lastSize );
1470 
1471  mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1472 
1473  moveCanvasContents( true );
1474 
1475  updateScale();
1476 
1477  //refresh();
1478 
1479  emit extentsChanged();
1480 }
1481 
1482 void QgsMapCanvas::paintEvent( QPaintEvent *e )
1483 {
1484  // no custom event handling anymore
1485 
1486  QGraphicsView::paintEvent( e );
1487 } // paintEvent
1488 
1490 {
1491  QList<QGraphicsItem *> list = mScene->items();
1492  QList<QGraphicsItem *>::iterator it = list.begin();
1493  while ( it != list.end() )
1494  {
1495  QgsMapCanvasItem *item = dynamic_cast<QgsMapCanvasItem *>( *it );
1496 
1497  if ( item )
1498  {
1499  item->updatePosition();
1500  }
1501 
1502  ++it;
1503  }
1504 }
1505 
1506 
1507 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
1508 {
1509  // Zoom the map canvas in response to a mouse wheel event. Moving the
1510  // wheel forward (away) from the user zooms in
1511 
1512  QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
1513 
1514  if ( mMapTool )
1515  {
1516  mMapTool->wheelEvent( e );
1517  if ( e->isAccepted() )
1518  return;
1519  }
1520 
1521  double zoomFactor = mWheelZoomFactor;
1522 
1523  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1524  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( e->angleDelta().y() );
1525 
1526  if ( e->modifiers() & Qt::ControlModifier )
1527  {
1528  //holding ctrl while wheel zooming results in a finer zoom
1529  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1530  }
1531 
1532  double signedWheelFactor = e->angleDelta().y() > 0 ? 1 / zoomFactor : zoomFactor;
1533 
1534  // zoom map to mouse cursor by scaling
1535  QgsPointXY oldCenter = center();
1536  QgsPointXY mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
1537  QgsPointXY newCenter( mousePos.x() + ( ( oldCenter.x() - mousePos.x() ) * signedWheelFactor ),
1538  mousePos.y() + ( ( oldCenter.y() - mousePos.y() ) * signedWheelFactor ) );
1539 
1540  zoomByFactor( signedWheelFactor, &newCenter );
1541  e->accept();
1542 }
1543 
1544 void QgsMapCanvas::setWheelFactor( double factor )
1545 {
1546  mWheelZoomFactor = factor;
1547 }
1548 
1550 {
1551  // magnification is alreday handled in zoomByFactor
1552  zoomByFactor( 1 / mWheelZoomFactor );
1553 }
1554 
1556 {
1557  // magnification is alreday handled in zoomByFactor
1558  zoomByFactor( mWheelZoomFactor );
1559 }
1560 
1561 void QgsMapCanvas::zoomScale( double newScale )
1562 {
1563  zoomByFactor( newScale / scale() );
1564 }
1565 
1566 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
1567 {
1568  double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1569 
1570  if ( mScaleLocked )
1571  {
1573  }
1574  else
1575  {
1576  // transform the mouse pos to map coordinates
1579  r.scale( scaleFactor, &center );
1580  setExtent( r, true );
1581  refresh();
1582  }
1583 }
1584 
1585 void QgsMapCanvas::setScaleLocked( bool isLocked )
1586 {
1587  mScaleLocked = isLocked;
1588 }
1589 
1590 void QgsMapCanvas::mouseMoveEvent( QMouseEvent *e )
1591 {
1592  mCanvasProperties->mouseLastXY = e->pos();
1593 
1594  if ( mCanvasProperties->panSelectorDown )
1595  {
1596  panAction( e );
1597  }
1598  else if ( mZoomDragging )
1599  {
1600  mZoomRect.setBottomRight( e->pos() );
1601  mZoomRubberBand->setToCanvasRectangle( mZoomRect );
1602  mZoomRubberBand->show();
1603  }
1604  else
1605  {
1606  // call handler of current map tool
1607  if ( mMapTool )
1608  {
1609  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1610  mMapTool->canvasMoveEvent( me.get() );
1611  }
1612  }
1613 
1614  // show x y on status bar
1615  QPoint xy = e->pos();
1617  emit xyCoordinates( coord );
1618 }
1619 
1620 void QgsMapCanvas::setMapTool( QgsMapTool *tool, bool clean )
1621 {
1622  if ( !tool )
1623  return;
1624 
1625  if ( mMapTool )
1626  {
1627  if ( clean )
1628  mMapTool->clean();
1629 
1630  disconnect( mMapTool, &QObject::destroyed, this, &QgsMapCanvas::mapToolDestroyed );
1631  mMapTool->deactivate();
1632  }
1633 
1634  if ( ( tool->flags() & QgsMapTool::Transient )
1635  && mMapTool && !( mMapTool->flags() & QgsMapTool::Transient ) )
1636  {
1637  // if zoom or pan tool will be active, save old tool
1638  // to bring it back on right click
1639  // (but only if it wasn't also zoom or pan tool)
1640  mLastNonZoomMapTool = mMapTool;
1641  }
1642  else
1643  {
1644  mLastNonZoomMapTool = nullptr;
1645  }
1646 
1647  QgsMapTool *oldTool = mMapTool;
1648 
1649  // set new map tool and activate it
1650  mMapTool = tool;
1651  if ( mMapTool )
1652  {
1653  connect( mMapTool, &QObject::destroyed, this, &QgsMapCanvas::mapToolDestroyed );
1654  mMapTool->activate();
1655  }
1656 
1657  emit mapToolSet( mMapTool, oldTool );
1658 } // setMapTool
1659 
1661 {
1662  if ( mMapTool && mMapTool == tool )
1663  {
1664  mMapTool->deactivate();
1665  mMapTool = nullptr;
1666  emit mapToolSet( nullptr, mMapTool );
1667  setCursor( Qt::ArrowCursor );
1668  }
1669 
1670  if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1671  {
1672  mLastNonZoomMapTool = nullptr;
1673  }
1674 }
1675 
1676 void QgsMapCanvas::setCanvasColor( const QColor &color )
1677 {
1678  if ( canvasColor() == color )
1679  return;
1680 
1681  // background of map's pixmap
1682  mSettings.setBackgroundColor( color );
1683 
1684  // background of the QGraphicsView
1685  QBrush bgBrush( color );
1686  setBackgroundBrush( bgBrush );
1687 #if 0
1688  QPalette palette;
1689  palette.setColor( backgroundRole(), color );
1690  setPalette( palette );
1691 #endif
1692 
1693  // background of QGraphicsScene
1694  mScene->setBackgroundBrush( bgBrush );
1695 
1696  emit canvasColorChanged();
1697 }
1698 
1700 {
1701  return mScene->backgroundBrush().color();
1702 }
1703 
1704 void QgsMapCanvas::setSelectionColor( const QColor &color )
1705 {
1706  mSettings.setSelectionColor( color );
1707 }
1708 
1710 {
1711  return mSettings.selectionColor();
1712 }
1713 
1715 {
1716  return mapSettings().layers().size();
1717 } // layerCount
1718 
1719 
1720 QList<QgsMapLayer *> QgsMapCanvas::layers() const
1721 {
1722  return mapSettings().layers();
1723 }
1724 
1726 {
1727  // called when a layer has changed visibility setting
1728  refresh();
1729 }
1730 
1731 void QgsMapCanvas::freeze( bool frozen )
1732 {
1733  mFrozen = frozen;
1734 }
1735 
1737 {
1738  return mFrozen;
1739 }
1740 
1742 {
1743  return mapSettings().mapUnitsPerPixel();
1744 }
1745 
1747 {
1748  return mapSettings().mapUnits();
1749 }
1750 
1751 QMap<QString, QString> QgsMapCanvas::layerStyleOverrides() const
1752 {
1753  return mSettings.layerStyleOverrides();
1754 }
1755 
1756 void QgsMapCanvas::setLayerStyleOverrides( const QMap<QString, QString> &overrides )
1757 {
1758  if ( overrides == mSettings.layerStyleOverrides() )
1759  return;
1760 
1761  mSettings.setLayerStyleOverrides( overrides );
1762  clearCache();
1764 }
1765 
1766 void QgsMapCanvas::setTheme( const QString &theme )
1767 {
1768  if ( mTheme == theme )
1769  return;
1770 
1771  clearCache();
1772  if ( theme.isEmpty() || !QgsProject::instance()->mapThemeCollection()->hasMapTheme( theme ) )
1773  {
1774  mTheme.clear();
1775  mSettings.setLayerStyleOverrides( QMap< QString, QString>() );
1776  setLayers( QgsProject::instance()->mapThemeCollection()->masterVisibleLayers() );
1777  emit themeChanged( QString() );
1778  }
1779  else
1780  {
1781  mTheme = theme;
1782  setLayersPrivate( QgsProject::instance()->mapThemeCollection()->mapThemeVisibleLayers( mTheme ) );
1783  emit themeChanged( theme );
1784  }
1785 }
1786 
1788 {
1789  mRenderFlag = flag;
1790 
1791  if ( mRenderFlag )
1792  {
1793  refresh();
1794  }
1795  else
1796  stopRendering();
1797 }
1798 
1799 #if 0
1800 void QgsMapCanvas::connectNotify( const char *signal )
1801 {
1802  Q_UNUSED( signal );
1803  QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
1804 } //connectNotify
1805 #endif
1806 
1807 void QgsMapCanvas::layerRepaintRequested( bool deferred )
1808 {
1809  if ( !deferred )
1810  refresh();
1811 }
1812 
1813 void QgsMapCanvas::autoRefreshTriggered()
1814 {
1815  if ( mJob )
1816  {
1817  // canvas is currently being redrawn, so we skip this auto refresh
1818  // otherwise we could get stuck in the situation where an auto refresh is triggered
1819  // too often to allow the canvas to ever finish rendering
1820  return;
1821  }
1822 
1823  refresh();
1824 }
1825 
1826 void QgsMapCanvas::updateAutoRefreshTimer()
1827 {
1828  // min auto refresh interval stores the smallest interval between layer auto refreshes. We automatically
1829  // trigger a map refresh on this minimum interval
1830  int minAutoRefreshInterval = -1;
1831  Q_FOREACH ( QgsMapLayer *layer, mSettings.layers() )
1832  {
1833  if ( layer->hasAutoRefreshEnabled() && layer->autoRefreshInterval() > 0 )
1834  minAutoRefreshInterval = minAutoRefreshInterval > 0 ? std::min( layer->autoRefreshInterval(), minAutoRefreshInterval ) : layer->autoRefreshInterval();
1835  }
1836 
1837  if ( minAutoRefreshInterval > 0 )
1838  {
1839  mAutoRefreshTimer.setInterval( minAutoRefreshInterval );
1840  mAutoRefreshTimer.start();
1841  }
1842  else
1843  {
1844  mAutoRefreshTimer.stop();
1845  }
1846 }
1847 
1848 void QgsMapCanvas::projectThemesChanged()
1849 {
1850  if ( mTheme.isEmpty() )
1851  return;
1852 
1853  if ( !QgsProject::instance()->mapThemeCollection()->hasMapTheme( mTheme ) )
1854  {
1855  // theme has been removed - stop following
1856  setTheme( QString() );
1857  }
1858 
1859 }
1860 
1862 {
1863  return mMapTool;
1864 }
1865 
1866 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
1867 {
1868  // move map image and other items to standard position
1869  moveCanvasContents( true ); // true means reset
1870 
1871  // use start and end box points to calculate the extent
1872  QgsPointXY start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
1874 
1875  // modify the center
1876  double dx = end.x() - start.x();
1877  double dy = end.y() - start.y();
1878  QgsPointXY c = center();
1879  c.set( c.x() - dx, c.y() - dy );
1880  setCenter( c );
1881 
1882  refresh();
1883 }
1884 
1885 void QgsMapCanvas::panAction( QMouseEvent *e )
1886 {
1887  Q_UNUSED( e );
1888 
1889  // move all map canvas items
1891 }
1892 
1894 {
1895  QPoint pnt( 0, 0 );
1896  if ( !reset )
1897  pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
1898 
1899  setSceneRect( -pnt.x(), -pnt.y(), viewport()->size().width(), viewport()->size().height() );
1900 }
1901 
1903 {
1904  return mCanvasProperties->mouseLastXY;
1905 }
1906 
1907 void QgsMapCanvas::setPreviewModeEnabled( bool previewEnabled )
1908 {
1909  if ( !mPreviewEffect )
1910  {
1911  return;
1912  }
1913 
1914  mPreviewEffect->setEnabled( previewEnabled );
1915 }
1916 
1918 {
1919  if ( !mPreviewEffect )
1920  {
1921  return false;
1922  }
1923 
1924  return mPreviewEffect->isEnabled();
1925 }
1926 
1928 {
1929  if ( !mPreviewEffect )
1930  {
1931  return;
1932  }
1933 
1934  mPreviewEffect->setMode( mode );
1935 }
1936 
1938 {
1939  if ( !mPreviewEffect )
1940  {
1942  }
1943 
1944  return mPreviewEffect->mode();
1945 }
1946 
1948 {
1949  if ( !mSnappingUtils )
1950  {
1951  // associate a dummy instance, but better than null pointer
1952  QgsMapCanvas *c = const_cast<QgsMapCanvas *>( this );
1953  c->mSnappingUtils = new QgsMapCanvasSnappingUtils( c, c );
1954  }
1955  return mSnappingUtils;
1956 }
1957 
1959 {
1960  mSnappingUtils = utils;
1961 }
1962 
1963 void QgsMapCanvas::readProject( const QDomDocument &doc )
1964 {
1965  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "mapcanvas" ) );
1966  if ( nodes.count() )
1967  {
1968  QDomNode node = nodes.item( 0 );
1969 
1970  // Search the specific MapCanvas node using the name
1971  if ( nodes.count() > 1 )
1972  {
1973  for ( int i = 0; i < nodes.size(); ++i )
1974  {
1975  QDomElement elementNode = nodes.at( i ).toElement();
1976 
1977  if ( elementNode.hasAttribute( QStringLiteral( "name" ) ) && elementNode.attribute( QStringLiteral( "name" ) ) == objectName() )
1978  {
1979  node = nodes.at( i );
1980  break;
1981  }
1982  }
1983  }
1984 
1985  QgsMapSettings tmpSettings;
1986  tmpSettings.readXml( node );
1987  if ( objectName() != QStringLiteral( "theMapCanvas" ) )
1988  {
1989  // never manually set the crs for the main canvas - this is instead connected to the project CRS
1990  setDestinationCrs( tmpSettings.destinationCrs() );
1991  }
1992  setExtent( tmpSettings.extent() );
1993  setRotation( tmpSettings.rotation() );
1995 
1996  clearExtentHistory(); // clear the extent history on project load
1997 
1998  QDomElement elem = node.toElement();
1999  if ( elem.hasAttribute( QStringLiteral( "theme" ) ) )
2000  {
2001  if ( QgsProject::instance()->mapThemeCollection()->hasMapTheme( elem.attribute( QStringLiteral( "theme" ) ) ) )
2002  {
2003  setTheme( elem.attribute( QStringLiteral( "theme" ) ) );
2004  }
2005  }
2006  setAnnotationsVisible( elem.attribute( QStringLiteral( "annotationsVisible" ), QStringLiteral( "1" ) ).toInt() );
2007  }
2008  else
2009  {
2010  QgsDebugMsg( "Couldn't read mapcanvas information from project" );
2011  }
2012 }
2013 
2014 void QgsMapCanvas::writeProject( QDomDocument &doc )
2015 {
2016  // create node "mapcanvas" and call mMapRenderer->writeXml()
2017 
2018  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
2019  if ( !nl.count() )
2020  {
2021  QgsDebugMsg( "Unable to find qgis element in project file" );
2022  return;
2023  }
2024  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element OK
2025 
2026  QDomElement mapcanvasNode = doc.createElement( QStringLiteral( "mapcanvas" ) );
2027  mapcanvasNode.setAttribute( QStringLiteral( "name" ), objectName() );
2028  if ( !mTheme.isEmpty() )
2029  mapcanvasNode.setAttribute( QStringLiteral( "theme" ), mTheme );
2030  mapcanvasNode.setAttribute( QStringLiteral( "annotationsVisible" ), mAnnotationsVisible );
2031  qgisNode.appendChild( mapcanvasNode );
2032 
2033  mSettings.writeXml( mapcanvasNode, doc );
2034  // TODO: store only units, extent, projections, dest CRS
2035 }
2036 
2037 #if 0
2038 void QgsMapCanvas::getDatumTransformInfo( const QgsCoordinateReferenceSystem &source, const QgsCoordinateReferenceSystem &destination )
2039 {
2040  if ( !source.isValid() || !destination.isValid() )
2041  return;
2042 
2043  //check if default datum transformation available
2044  QgsSettings s;
2045  QString settingsString = "/Projections/" + source.authid() + "//" + destination.authid();
2046  QVariant defaultSrcTransform = s.value( settingsString + "_srcTransform" );
2047  QVariant defaultDestTransform = s.value( settingsString + "_destTransform" );
2048  if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
2049  {
2050  int sourceDatumTransform = defaultSrcTransform.toInt();
2051  int destinationDatumTransform = defaultDestTransform.toInt();
2052 
2054  context.addSourceDestinationDatumTransform( source, destination, sourceDatumTransform, destinationDatumTransform );
2056  return;
2057  }
2058 
2059  if ( !s.value( QStringLiteral( "/Projections/showDatumTransformDialog" ), false ).toBool() )
2060  {
2061  return;
2062  }
2063 
2064  //if several possibilities: present dialog
2065  QgsDatumTransformDialog d( source, destination );
2066  if ( d.availableTransformationCount() > 1 )
2067  d.exec();
2068 }
2069 #endif
2070 
2071 void QgsMapCanvas::zoomByFactor( double scaleFactor, const QgsPointXY *center )
2072 {
2073  if ( mScaleLocked )
2074  {
2075  // zoom map to mouse cursor by magnifying
2077  }
2078  else
2079  {
2081  r.scale( scaleFactor, center );
2082  setExtent( r, true );
2083  refresh();
2084  }
2085 }
2086 
2088 {
2089  // Find out which layer it was that sent the signal.
2090  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
2091  emit selectionChanged( layer );
2092  refresh();
2093 }
2094 
2095 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent *e )
2096 {
2097  // By default graphics view delegates the drag events to graphics items.
2098  // But we do not want that and by ignoring the drag enter we let the
2099  // parent (e.g. QgisApp) to handle drops of map layers etc.
2100  e->ignore();
2101 }
2102 
2103 void QgsMapCanvas::mapToolDestroyed()
2104 {
2105  QgsDebugMsg( "maptool destroyed" );
2106  mMapTool = nullptr;
2107 }
2108 
2109 bool QgsMapCanvas::event( QEvent *e )
2110 {
2111  if ( !QTouchDevice::devices().empty() )
2112  {
2113  if ( e->type() == QEvent::Gesture )
2114  {
2115  // call handler of current map tool
2116  if ( mMapTool )
2117  {
2118  return mMapTool->gestureEvent( static_cast<QGestureEvent *>( e ) );
2119  }
2120  }
2121  }
2122 
2123  // pass other events to base class
2124  return QGraphicsView::event( e );
2125 }
2126 
2128 {
2129  // reload all layers in canvas
2130  for ( int i = 0; i < layerCount(); i++ )
2131  {
2132  QgsMapLayer *l = layer( i );
2133  if ( l )
2134  l->reload();
2135  }
2136 
2137  // clear the cache
2138  clearCache();
2139 
2140  // and then refresh
2141  refresh();
2142 }
2143 
2145 {
2146  while ( mRefreshScheduled || mJob )
2147  {
2148  QgsApplication::processEvents();
2149  }
2150 }
2151 
2153 {
2154  mSettings.setSegmentationTolerance( tolerance );
2155 }
2156 
2158 {
2159  mSettings.setSegmentationToleranceType( type );
2160 }
2161 
2162 QList<QgsMapCanvasAnnotationItem *> QgsMapCanvas::annotationItems() const
2163 {
2164  QList<QgsMapCanvasAnnotationItem *> annotationItemList;
2165  QList<QGraphicsItem *> itemList = mScene->items();
2166  QList<QGraphicsItem *>::iterator it = itemList.begin();
2167  for ( ; it != itemList.end(); ++it )
2168  {
2169  QgsMapCanvasAnnotationItem *aItem = dynamic_cast< QgsMapCanvasAnnotationItem *>( *it );
2170  if ( aItem )
2171  {
2172  annotationItemList.push_back( aItem );
2173  }
2174  }
2175 
2176  return annotationItemList;
2177 }
2178 
2180 {
2181  mAnnotationsVisible = show;
2182  Q_FOREACH ( QgsMapCanvasAnnotationItem *item, annotationItems() )
2183  {
2184  item->setVisible( show );
2185  }
2186 }
2187 
2189 {
2190  mSettings.setLabelingEngineSettings( settings );
2191 }
2192 
2194 {
2195  return mSettings.labelingEngineSettings();
2196 }
2197 
2198 void QgsMapCanvas::startPreviewJobs()
2199 {
2200  stopPreviewJobs(); //just in case still running
2201  schedulePreviewJob( 0 );
2202 }
2203 
2204 void QgsMapCanvas::startPreviewJob( int number )
2205 {
2206  QgsRectangle mapRect = mSettings.visibleExtent();
2207 
2208  if ( number == 4 )
2209  number += 1;
2210 
2211  int j = number / 3;
2212  int i = number % 3;
2213 
2214  //copy settings, only update extent
2215  QgsMapSettings jobSettings = mSettings;
2216 
2217  double dx = ( i - 1 ) * mapRect.width();
2218  double dy = ( 1 - j ) * mapRect.height();
2219  QgsRectangle jobExtent = mapRect;
2220 
2221  jobExtent.setXMaximum( jobExtent.xMaximum() + dx );
2222  jobExtent.setXMinimum( jobExtent.xMinimum() + dx );
2223  jobExtent.setYMaximum( jobExtent.yMaximum() + dy );
2224  jobExtent.setYMinimum( jobExtent.yMinimum() + dy );
2225 
2226  jobSettings.setExtent( jobExtent );
2227  jobSettings.setFlag( QgsMapSettings::DrawLabeling, false );
2228  jobSettings.setFlag( QgsMapSettings::RenderPreviewJob, true );
2229 
2230  // truncate preview layers to fast layers
2231  const QList<QgsMapLayer *> layers = jobSettings.layers();
2232  QList< QgsMapLayer * > previewLayers;
2234  context.maxRenderingTimeMs = MAXIMUM_LAYER_PREVIEW_TIME_MS;
2235  for ( QgsMapLayer *layer : layers )
2236  {
2237  context.lastRenderingTimeMs = mLastLayerRenderTime.value( layer->id(), 0 );
2238  if ( !layer->dataProvider()->renderInPreview( context ) )
2239  {
2240  QgsDebugMsgLevel( QString( "Layer %1 not rendered because it does not match the renderInPreview criterion %2" ).arg( layer->id() ).arg( mLastLayerRenderTime.value( layer->id() ) ), 3 );
2241  continue;
2242  }
2243 
2244  previewLayers << layer;
2245  }
2246  jobSettings.setLayers( previewLayers );
2247 
2248  QgsMapRendererQImageJob *job = new QgsMapRendererSequentialJob( jobSettings );
2249  job->setProperty( "number", number );
2250  mPreviewJobs.append( job );
2251  connect( job, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
2252  job->start();
2253 }
2254 
2255 void QgsMapCanvas::stopPreviewJobs()
2256 {
2257  mPreviewTimer.stop();
2258  QList< QgsMapRendererQImageJob * >::const_iterator it = mPreviewJobs.constBegin();
2259  for ( ; it != mPreviewJobs.constEnd(); ++it )
2260  {
2261  if ( *it )
2262  {
2263  disconnect( *it, &QgsMapRendererJob::finished, this, &QgsMapCanvas::previewJobFinished );
2264  connect( *it, &QgsMapRendererQImageJob::finished, *it, &QgsMapRendererQImageJob::deleteLater );
2265  ( *it )->cancelWithoutBlocking();
2266  }
2267  }
2268  mPreviewJobs.clear();
2269 }
2270 
2271 void QgsMapCanvas::schedulePreviewJob( int number )
2272 {
2273  mPreviewTimer.setSingleShot( true );
2274  mPreviewTimer.setInterval( PREVIEW_JOB_DELAY_MS );
2275  disconnect( mPreviewTimerConnection );
2276  mPreviewTimerConnection = connect( &mPreviewTimer, &QTimer::timeout, this, [ = ]()
2277  {
2278  startPreviewJob( number );
2279  }
2280  );
2281  mPreviewTimer.start();
2282 }
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:90
void clearExtentHistory()
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
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:227
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:138
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:95
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 messageEmitted(const QString &title, const QString &message, QgsMessageBar::MessageLevel=QgsMessageBar::INFO)
emit a message (usually to be displayed in a message bar)
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:126
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:111
static QCursor getThemeCursor(const Cursor &cursor)
Helper to get a theme cursor.
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.
static void logMessage(const QString &message, const QString &tag=QString(), MessageLevel level=QgsMessageLog::WARNING)
add a message to the instance (and create it if necessary)
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:200
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:100
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:116
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 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:121
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.
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:166
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:85
double height() const
Returns the height of the rectangle.
Definition: qgsrectangle.h:145
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.
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