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