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