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