QGIS API Documentation  2.99.0-Master (75367e4)
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 <QSettings>
34 #include <QTextStream>
35 #include <QResizeEvent>
36 #include <QString>
37 #include <QStringList>
38 #include <QWheelEvent>
39 
40 #include "qgis.h"
42 #include "qgsapplication.h"
43 #include "qgscsexception.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 "qgsmessagelog.h"
60 #include "qgsmessageviewer.h"
61 #include "qgspallabeling.h"
62 #include "qgsproject.h"
63 #include "qgsrubberband.h"
64 #include "qgsvectorlayer.h"
65 #include "qgscursors.h"
66 #include <math.h>
67 
68 
73 //TODO QGIS 3.0 - remove
75 {
76  public:
78  : mouseButtonDown( false )
79  , panSelectorDown( false )
80  { }
81 
84 
86  QPoint mouseLastXY;
87 
90 
93 };
94 
95 
96 
97 QgsMapCanvas::QgsMapCanvas( QWidget * parent )
98  : QGraphicsView( parent )
100  , mMap( nullptr )
101  , mFrozen( false )
102  , mRefreshScheduled( false )
103  , mRenderFlag( true ) // by default, the canvas is rendered
104  , mCurrentLayer( nullptr )
105  , mScene( nullptr )
106  , mMapTool( nullptr )
107  , mLastNonZoomMapTool( nullptr )
108  , mLastExtentIndex( -1 )
109  , mWheelZoomFactor( 2.0 )
110  , mJob( nullptr )
111  , mJobCanceled( false )
112  , mLabelingResults( nullptr )
113  , mUseParallelRendering( false )
114  , mDrawRenderingStats( false )
115  , mCache( nullptr )
116  , mResizeTimer( nullptr )
117  , mPreviewEffect( nullptr )
118  , mSnappingUtils( nullptr )
119  , mScaleLocked( false )
120  , mExpressionContextScope( tr( "Map Canvas" ) )
121  , mZoomDragging( false )
122 {
123  mScene = new QGraphicsScene();
124  setScene( mScene );
125  setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
126  setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
127  setMouseTracking( true );
128  setFocusPolicy( Qt::StrongFocus );
129 
130  mResizeTimer = new QTimer( this );
131  mResizeTimer->setSingleShot( true );
132  connect( mResizeTimer, SIGNAL( timeout() ), this, SLOT( refresh() ) );
133 
134  // create map canvas item which will show the map
135  mMap = new QgsMapCanvasMap( this );
136 
137  // project handling
138  connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ),
139  this, SLOT( readProject( const QDomDocument & ) ) );
140  connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ),
141  this, SLOT( writeProject( QDomDocument & ) ) );
142 
146 
147  //segmentation parameters
148  QSettings settings;
149  double segmentationTolerance = settings.value( QStringLiteral( "/qgis/segmentationTolerance" ), "0.01745" ).toDouble();
150  QgsAbstractGeometry::SegmentationToleranceType toleranceType = QgsAbstractGeometry::SegmentationToleranceType( settings.value( QStringLiteral( "/qgis/segmentationToleranceType" ), 0 ).toInt() );
151  mSettings.setSegmentationTolerance( segmentationTolerance );
152  mSettings.setSegmentationToleranceType( toleranceType );
153 
154  mWheelZoomFactor = settings.value( QStringLiteral( "/qgis/zoom_factor" ), 2 ).toDouble();
155 
156  QSize s = viewport()->size();
157  mSettings.setOutputSize( s );
158  setSceneRect( 0, 0, s.width(), s.height() );
159  mScene->setSceneRect( QRectF( 0, 0, s.width(), s.height() ) );
160 
161  moveCanvasContents( true );
162 
163  connect( &mMapUpdateTimer, SIGNAL( timeout() ), SLOT( mapUpdateTimeout() ) );
164  mMapUpdateTimer.setInterval( 250 );
165 
166 #ifdef Q_OS_WIN
167  // Enable touch event on Windows.
168  // Qt on Windows needs to be told it can take touch events or else it ignores them.
169  grabGesture( Qt::PinchGesture );
170  viewport()->setAttribute( Qt::WA_AcceptTouchEvents );
171 #endif
172 
173  mPreviewEffect = new QgsPreviewEffect( this );
174  viewport()->setGraphicsEffect( mPreviewEffect );
175 
176  QPixmap zoomPixmap = QPixmap(( const char ** )( zoom_in ) );
177  mZoomCursor = QCursor( zoomPixmap, 7, 7 );
178 
179  connect( &mAutoRefreshTimer, &QTimer::timeout, this, &QgsMapCanvas::autoRefreshTriggered );
180 
181  setInteractive( false );
182 
183  refresh();
184 
185 } // QgsMapCanvas ctor
186 
187 
189 {
190  if ( mMapTool )
191  {
192  mMapTool->deactivate();
193  mMapTool = nullptr;
194  }
195  mLastNonZoomMapTool = nullptr;
196 
197  // delete canvas items prior to deleting the canvas
198  // because they might try to update canvas when it's
199  // already being destructed, ends with segfault
200  QList<QGraphicsItem*> list = mScene->items();
201  QList<QGraphicsItem*>::iterator it = list.begin();
202  while ( it != list.end() )
203  {
204  QGraphicsItem* item = *it;
205  delete item;
206  ++it;
207  }
208 
209  mScene->deleteLater(); // crashes in python tests on windows
210 
211  // mCanvasProperties auto-deleted via QScopedPointer
212  // CanvasProperties struct has its own dtor for freeing resources
213 
214  if ( mJob )
215  {
216  mJob->cancel();
217  Q_ASSERT( !mJob );
218  }
219 
220  delete mCache;
221 
222  delete mLabelingResults;
223 
224 } // dtor
225 
227 {
228  // do not go higher or lower than min max magnification ratio
229  double magnifierMin = QgisGui::CANVAS_MAGNIFICATION_MIN;
230  double magnifierMax = QgisGui::CANVAS_MAGNIFICATION_MAX;
231  factor = qBound( magnifierMin, factor, magnifierMax );
232 
233  // the magnifier widget is in integer percent
234  if ( !qgsDoubleNear( factor, mSettings.magnificationFactor(), 0.01 ) )
235  {
236  mSettings.setMagnificationFactor( factor );
237  refresh();
238  emit magnificationChanged( factor );
239  }
240 }
241 
243 {
244  return mSettings.magnificationFactor();
245 }
246 
248 {
249  mSettings.setFlag( QgsMapSettings::Antialiasing, theFlag );
250 } // anti aliasing
251 
253 {
254  mSettings.setFlag( QgsMapSettings::RenderMapTile, theFlag );
255 }
256 
258 {
259  QList<QgsMapLayer*> layers = mapSettings().layers();
260  if ( index >= 0 && index < ( int ) layers.size() )
261  return layers[index];
262  else
263  return nullptr;
264 }
265 
266 
268 {
269  mCurrentLayer = layer;
270  emit currentLayerChanged( layer );
271 }
272 
274 {
275  return mapSettings().scale();
276 } // scale
277 
279 {
280  return nullptr != mJob;
281 } // isDrawing
282 
283 // return the current coordinate transform based on the extents and
284 // device size
286 {
287  return &mapSettings().mapToPixel();
288 }
289 
290 void QgsMapCanvas::setLayers( const QList<QgsMapLayer*>& layers )
291 {
292  QList<QgsMapLayer*> oldLayers = mSettings.layers();
293 
294  // update only if needed
295  if ( layers == oldLayers )
296  return;
297 
298  Q_FOREACH ( QgsMapLayer* layer, oldLayers )
299  {
300  disconnect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapCanvas::layerRepaintRequested );
301  disconnect( layer, &QgsMapLayer::crsChanged, this, &QgsMapCanvas::layerCrsChange );
302  disconnect( layer, &QgsMapLayer::autoRefreshIntervalChanged, this, &QgsMapCanvas::updateAutoRefreshTimer );
303  if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( layer ) )
304  {
306  }
307  }
308 
309  mSettings.setLayers( layers );
310 
311  Q_FOREACH ( QgsMapLayer* layer, layers )
312  {
313  connect( layer, &QgsMapLayer::repaintRequested, this, &QgsMapCanvas::layerRepaintRequested );
314  connect( layer, &QgsMapLayer::crsChanged, this, &QgsMapCanvas::layerCrsChange );
315  connect( layer, &QgsMapLayer::autoRefreshIntervalChanged, this, &QgsMapCanvas::updateAutoRefreshTimer );
316  if ( QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer *>( layer ) )
317  {
319  }
320  }
322 
323  QgsDebugMsg( "Layers have changed, refreshing" );
324  emit layersChanged();
325 
326  updateAutoRefreshTimer();
327  refresh();
328 }
329 
330 
332 {
333  return mSettings;
334 }
335 
337 {
338  if ( mSettings.hasCrsTransformEnabled() == enabled )
339  return;
340 
341  mSettings.setCrsTransformEnabled( enabled );
342 
344 
345  refresh();
346 
347  emit hasCrsTransformEnabledChanged( enabled );
348 }
349 
351 {
352  if ( mSettings.destinationCrs() == crs )
353  return;
354 
355  // try to reproject current extent to the new one
356  QgsRectangle rect;
357  if ( !mSettings.visibleExtent().isEmpty() )
358  {
359  QgsCoordinateTransform transform( mSettings.destinationCrs(), crs );
360  try
361  {
362  rect = transform.transformBoundingBox( mSettings.visibleExtent() );
363  }
364  catch ( QgsCsException &e )
365  {
366  Q_UNUSED( e );
367  QgsDebugMsg( QString( "Transform error caught: %1" ).arg( e.what() ) );
368  }
369  }
370 
371  if ( !mSettings.hasCrsTransformEnabled() )
372  {
373  mSettings.setMapUnits( crs.mapUnits() );
374  }
375  if ( !rect.isEmpty() )
376  {
377  setExtent( rect );
378  }
379 
380  QgsDebugMsg( "refreshing after destination CRS changed" );
381  refresh();
382 
383  mSettings.setDestinationCrs( crs );
384 
386 
387  emit destinationCrsChanged();
388 }
389 
391 {
392  return mLabelingResults;
393 }
394 
396 {
397  if ( enabled == isCachingEnabled() )
398  return;
399 
400  if ( mJob && mJob->isActive() )
401  {
402  // wait for the current rendering to finish, before touching the cache
403  mJob->waitForFinished();
404  }
405 
406  if ( enabled )
407  {
408  mCache = new QgsMapRendererCache;
409  }
410  else
411  {
412  delete mCache;
413  mCache = nullptr;
414  }
415 }
416 
418 {
419  return nullptr != mCache;
420 }
421 
423 {
424  if ( mCache )
425  mCache->clear();
426 }
427 
429 {
430  mUseParallelRendering = enabled;
431 }
432 
434 {
435  return mUseParallelRendering;
436 }
437 
438 void QgsMapCanvas::setMapUpdateInterval( int timeMilliseconds )
439 {
440  mMapUpdateTimer.setInterval( timeMilliseconds );
441 }
442 
444 {
445  return mMapUpdateTimer.interval();
446 }
447 
448 
450 {
451  return mCurrentLayer;
452 }
453 
454 
456 {
457  if ( !mSettings.hasValidSettings() )
458  {
459  QgsDebugMsg( "CANVAS refresh - invalid settings -> nothing to do" );
460  return;
461  }
462 
463  if ( !mRenderFlag || mFrozen ) // do we really need two flags controlling rendering?
464  {
465  QgsDebugMsg( "CANVAS render flag off" );
466  return;
467  }
468 
469  if ( mRefreshScheduled )
470  {
471  QgsDebugMsg( "CANVAS refresh already scheduled" );
472  return;
473  }
474 
475  mRefreshScheduled = true;
476 
477  QgsDebugMsg( "CANVAS refresh scheduling" );
478 
479  // schedule a refresh
480  QTimer::singleShot( 1, this, SLOT( refreshMap() ) );
481 } // refresh
482 
483 void QgsMapCanvas::refreshMap()
484 {
485  Q_ASSERT( mRefreshScheduled );
486 
487  QgsDebugMsgLevel( "CANVAS refresh!", 3 );
488 
489  stopRendering(); // if any...
490 
491  //build the expression context
492  QgsExpressionContext expressionContext;
493  expressionContext << QgsExpressionContextUtils::globalScope()
496  << new QgsExpressionContextScope( mExpressionContextScope );
497 
498  mSettings.setExpressionContext( expressionContext );
499 
500  // create the renderer job
501  Q_ASSERT( !mJob );
502  mJobCanceled = false;
503  if ( mUseParallelRendering )
504  mJob = new QgsMapRendererParallelJob( mSettings );
505  else
506  mJob = new QgsMapRendererSequentialJob( mSettings );
507  connect( mJob, SIGNAL( finished() ), SLOT( rendererJobFinished() ) );
508  mJob->setCache( mCache );
509 
510  QStringList layersForGeometryCache;
511  Q_FOREACH ( QgsMapLayer* layer, mSettings.layers() )
512  {
513  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( layer ) )
514  {
515  if ( vl->isEditable() )
516  layersForGeometryCache << vl->id();
517  }
518  }
519  mJob->setRequestedGeometryCacheForLayers( layersForGeometryCache );
520 
521  mJob->start();
522 
523  // from now on we can accept refresh requests again
524  // this must be reset only after the job has been started, because
525  // some providers (yes, it's you WCS and AMS!) during preparation
526  // do network requests and start an internal event loop, which may
527  // end up calling refresh() and would schedule another refresh,
528  // deleting the one we have just started.
529  mRefreshScheduled = false;
530 
531  mMapUpdateTimer.start();
532 
533  emit renderStarting();
534 }
535 
536 
537 void QgsMapCanvas::rendererJobFinished()
538 {
539  QgsDebugMsg( QString( "CANVAS finish! %1" ).arg( !mJobCanceled ) );
540 
541  mMapUpdateTimer.stop();
542 
543  // TODO: would be better to show the errors in message bar
544  Q_FOREACH ( const QgsMapRendererJob::Error& error, mJob->errors() )
545  {
546  QgsMessageLog::logMessage( error.layerID + " :: " + error.message, tr( "Rendering" ) );
547  }
548 
549  if ( !mJobCanceled )
550  {
551  // take labeling results before emitting renderComplete, so labeling map tools
552  // connected to signal work with correct results
553  if ( !mJob->usedCachedLabels() )
554  {
555  delete mLabelingResults;
556  mLabelingResults = mJob->takeLabelingResults();
557  }
558 
559  QImage img = mJob->renderedImage();
560 
561  // emit renderComplete to get our decorations drawn
562  QPainter p( &img );
563  emit renderComplete( &p );
564 
565  QSettings settings;
566  if ( settings.value( QStringLiteral( "/Map/logCanvasRefreshEvent" ), false ).toBool() )
567  {
568  QString logMsg = tr( "Canvas refresh: %1 ms" ).arg( mJob->renderingTime() );
569  QgsMessageLog::logMessage( logMsg, tr( "Rendering" ) );
570  }
571 
572  if ( mDrawRenderingStats )
573  {
574  int w = img.width(), h = img.height();
575  QFont fnt = p.font();
576  fnt.setBold( true );
577  p.setFont( fnt );
578  int lh = p.fontMetrics().height() * 2;
579  QRect r( 0, h - lh, w, lh );
580  p.setPen( Qt::NoPen );
581  p.setBrush( QColor( 0, 0, 0, 110 ) );
582  p.drawRect( r );
583  p.setPen( Qt::white );
584  QString msg = QStringLiteral( "%1 :: %2 ms" ).arg( mUseParallelRendering ? "PARALLEL" : "SEQUENTIAL" ).arg( mJob->renderingTime() );
585  p.drawText( r, msg, QTextOption( Qt::AlignCenter ) );
586  }
587 
588  p.end();
589 
590  mMap->setContent( img, imageRect( img, mSettings ) );
591  }
592 
593  // now we are in a slot called from mJob - do not delete it immediately
594  // so the class is still valid when the execution returns to the class
595  mJob->deleteLater();
596  mJob = nullptr;
597 
598  emit mapCanvasRefreshed();
599 }
600 
601 QgsRectangle QgsMapCanvas::imageRect( const QImage& img, const QgsMapSettings& mapSettings )
602 {
603  // This is a hack to pass QgsMapCanvasItem::setRect what it
604  // expects (encoding of position and size of the item)
605  const QgsMapToPixel& m2p = mapSettings.mapToPixel();
606  QgsPoint topLeft = m2p.toMapPoint( 0, 0 );
607  double res = m2p.mapUnitsPerPixel();
608  QgsRectangle rect( topLeft.x(), topLeft.y(), topLeft.x() + img.width()*res, topLeft.y() - img.height()*res );
609  return rect;
610 }
611 
612 void QgsMapCanvas::mapUpdateTimeout()
613 {
614  const QImage& img = mJob->renderedImage();
615  mMap->setContent( img, imageRect( img, mSettings ) );
616 }
617 
619 {
620  if ( mJob )
621  {
622  QgsDebugMsg( "CANVAS stop rendering!" );
623  mJobCanceled = true;
624  mJob->cancel();
625  Q_ASSERT( !mJob ); // no need to delete here: already deleted in finished()
626  }
627 }
628 
629 //the format defaults to "PNG" if not specified
630 void QgsMapCanvas::saveAsImage( const QString& theFileName, QPixmap * theQPixmap, const QString& theFormat )
631 {
632  QPainter painter;
633  QImage image;
634 
635  //
636  //check if the optional QPaintDevice was supplied
637  //
638  if ( theQPixmap )
639  {
640  image = theQPixmap->toImage();
641  painter.begin( &image );
642 
643  // render
644  QgsMapRendererCustomPainterJob job( mSettings, &painter );
645  job.start();
646  job.waitForFinished();
647  emit renderComplete( &painter );
648  }
649  else //use the map view
650  {
651  image = mMap->contentImage().copy();
652  painter.begin( &image );
653  }
654 
655  // draw annotations
656  QStyleOptionGraphicsItem option;
657  option.initFrom( this );
658  QGraphicsItem* item = nullptr;
659  QListIterator<QGraphicsItem*> i( items() );
660  i.toBack();
661  while ( i.hasPrevious() )
662  {
663  item = i.previous();
664 
665  if ( !item || dynamic_cast< QgsMapCanvasAnnotationItem* >( item ) )
666  {
667  continue;
668  }
669 
670  painter.save();
671 
672  QPointF itemScenePos = item->scenePos();
673  painter.translate( itemScenePos.x(), itemScenePos.y() );
674 
675  item->paint( &painter, &option );
676 
677  painter.restore();
678  }
679 
680  painter.end();
681  image.save( theFileName, theFormat.toLocal8Bit().data() );
682 
683  //create a world file to go with the image...
685  QString myHeader;
686  // note: use 17 places of precision for all numbers output
687  //Pixel XDim
688  myHeader += qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
689  //Rotation on y axis - hard coded
690  myHeader += QLatin1String( "0 \r\n" );
691  //Rotation on x axis - hard coded
692  myHeader += QLatin1String( "0 \r\n" );
693  //Pixel YDim - almost always negative - see
694  //http://en.wikipedia.org/wiki/World_file#cite_note-2
695  myHeader += '-' + qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
696  //Origin X (center of top left cell)
697  myHeader += qgsDoubleToString( myRect.xMinimum() + ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
698  //Origin Y (center of top left cell)
699  myHeader += qgsDoubleToString( myRect.yMaximum() - ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
700  QFileInfo myInfo = QFileInfo( theFileName );
701  // build the world file name
702  QString outputSuffix = myInfo.suffix();
703  QString myWorldFileName = myInfo.absolutePath() + '/' + myInfo.baseName() + '.'
704  + outputSuffix.at( 0 ) + outputSuffix.at( myInfo.suffix().size() - 1 ) + 'w';
705  QFile myWorldFile( myWorldFileName );
706  if ( !myWorldFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) ) //don't use QIODevice::Text
707  {
708  return;
709  }
710  QTextStream myStream( &myWorldFile );
711  myStream << myHeader;
712 } // saveAsImage
713 
714 
715 
717 {
718  return mapSettings().visibleExtent();
719 } // extent
720 
722 {
723  return mapSettings().fullExtent();
724 } // extent
725 
726 
727 void QgsMapCanvas::setExtent( const QgsRectangle& r, bool magnified )
728 {
729  QgsRectangle current = extent();
730 
731  if (( r == current ) && magnified )
732  return;
733 
734  if ( r.isEmpty() )
735  {
736  if ( !mSettings.hasValidSettings() )
737  {
738  // we can't even just move the map center
739  QgsDebugMsg( "Empty extent - ignoring" );
740  return;
741  }
742 
743  // ### QGIS 3: do not allow empty extent - require users to call setCenter() explicitly
744  QgsDebugMsg( "Empty extent - keeping old scale with new center!" );
745  setCenter( r.center() );
746  }
747  else
748  {
749  mSettings.setExtent( r, magnified );
750  }
751  emit extentsChanged();
752  updateScale();
753  if ( mLastExtent.size() > 20 )
754  mLastExtent.removeAt( 0 );
755 
756  //clear all extent items after current index
757  for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
758  {
759  mLastExtent.removeAt( i );
760  }
761 
762  mLastExtent.append( extent() );
763 
764  // adjust history to no more than 20
765  if ( mLastExtent.size() > 20 )
766  {
767  mLastExtent.removeAt( 0 );
768  }
769 
770  // the last item is the current extent
771  mLastExtentIndex = mLastExtent.size() - 1;
772 
773  // update controls' enabled state
774  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
775  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
776  // notify canvas items of change
778 
779 } // setExtent
780 
782 {
784  double x = center.x();
785  double y = center.y();
786  setExtent(
787  QgsRectangle(
788  x - r.width() / 2.0, y - r.height() / 2.0,
789  x + r.width() / 2.0, y + r.height() / 2.0
790  ),
791  true
792  );
793 } // setCenter
794 
796 {
798  return r.center();
799 }
800 
801 
803 {
804  return mapSettings().rotation();
805 } // rotation
806 
807 void QgsMapCanvas::setRotation( double degrees )
808 {
809  double current = rotation();
810 
811  if ( degrees == current )
812  return;
813 
814  mSettings.setRotation( degrees );
815  emit rotationChanged( degrees );
816  emit extentsChanged(); // visible extent changes with rotation
817 
818  // notify canvas items of change (needed?)
820 
821 } // setRotation
822 
823 
825 {
826  emit scaleChanged( mapSettings().scale() );
827 }
828 
829 
831 {
833  // If the full extent is an empty set, don't do the zoom
834  if ( !extent.isEmpty() )
835  {
836  // Add a 5% margin around the full extent
837  extent.scale( 1.05 );
838  setExtent( extent );
839  }
840  refresh();
841 
842 } // zoomToFullExtent
843 
844 
845 
847 {
848  if ( mLastExtentIndex > 0 )
849  {
850  mLastExtentIndex--;
851  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
852  emit extentsChanged();
853  updateScale();
854  refresh();
855  // update controls' enabled state
856  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
857  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
858  // notify canvas items of change
860  }
861 
862 } // zoomToPreviousExtent
863 
865 {
866  if ( mLastExtentIndex < mLastExtent.size() - 1 )
867  {
868  mLastExtentIndex++;
869  mSettings.setExtent( mLastExtent[mLastExtentIndex] );
870  emit extentsChanged();
871  updateScale();
872  refresh();
873  // update controls' enabled state
874  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
875  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
876  // notify canvas items of change
878  }
879 }// zoomToNextExtent
880 
882 {
883  mLastExtent.clear(); // clear the zoom history list
884  mLastExtent.append( extent() ) ; // set the current extent in the list
885  mLastExtentIndex = mLastExtent.size() - 1;
886  // update controls' enabled state
887  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
888  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
889 }// clearExtentHistory
890 
891 
893 {
895 }
896 
898 {
899  if ( !layer )
900  {
901  // use current layer by default
902  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
903  }
904 
905  if ( !layer || layer->selectedFeatureCount() == 0 )
906  return;
907 
909  zoomToFeatureExtent( rect );
910 } // zoomToSelected
911 
913 {
914  // no selected features, only one selected point feature
915  //or two point features with the same x- or y-coordinates
916  if ( rect.isEmpty() )
917  {
918  // zoom in
919  QgsPoint c = rect.center();
920  rect = extent();
921  rect.scale( 1.0, &c );
922  }
923  //zoom to an area
924  else
925  {
926  // Expand rect to give a bit of space around the selected
927  // objects so as to keep them clear of the map boundaries
928  // The same 5% should apply to all margins.
929  rect.scale( 1.05 );
930  }
931 
932  setExtent( rect );
933  refresh();
934 }
935 
937 {
938  if ( !layer )
939  {
940  return;
941  }
942 
943  QgsRectangle bbox;
944  QString errorMsg;
945  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
946  {
947  zoomToFeatureExtent( bbox );
948  }
949  else
950  {
951  emit messageEmitted( tr( "Zoom to feature id failed" ), errorMsg, QgsMessageBar::WARNING );
952  }
953 
954 }
955 
957 {
958  if ( !layer )
959  {
960  return;
961  }
962 
963  QgsRectangle bbox;
964  QString errorMsg;
965  if ( boundingBoxOfFeatureIds( ids, layer, bbox, errorMsg ) )
966  {
967  setCenter( bbox.center() );
968  refresh();
969  }
970  else
971  {
972  emit messageEmitted( tr( "Pan to feature id failed" ), errorMsg, QgsMessageBar::WARNING );
973  }
974 }
975 
976 bool QgsMapCanvas::boundingBoxOfFeatureIds( const QgsFeatureIds& ids, QgsVectorLayer* layer, QgsRectangle& bbox, QString& errorMsg ) const
977 {
978  QgsFeatureIterator it = layer->getFeatures( QgsFeatureRequest().setFilterFids( ids ).setSubsetOfAttributes( QgsAttributeList() ) );
979  bbox.setMinimal();
980  QgsFeature fet;
981  int featureCount = 0;
982  errorMsg.clear();
983 
984  while ( it.nextFeature( fet ) )
985  {
986  QgsGeometry geom = fet.geometry();
987  if ( geom.isNull() )
988  {
989  errorMsg = tr( "Feature does not have a geometry" );
990  }
991  else if ( geom.geometry()->isEmpty() )
992  {
993  errorMsg = tr( "Feature geometry is empty" );
994  }
995  if ( !errorMsg.isEmpty() )
996  {
997  return false;
998  }
1000  bbox.combineExtentWith( r );
1001  featureCount++;
1002  }
1003 
1004  if ( featureCount != ids.count() )
1005  {
1006  errorMsg = tr( "Feature not found" );
1007  return false;
1008  }
1009 
1010  return true;
1011 }
1012 
1014 {
1015  if ( !layer )
1016  {
1017  // use current layer by default
1018  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1019  }
1020 
1021  if ( !layer || layer->selectedFeatureCount() == 0 )
1022  return;
1023 
1025  if ( !rect.isNull() )
1026  {
1027  setCenter( rect.center() );
1028  refresh();
1029  }
1030  else
1031  {
1032  emit messageEmitted( tr( "Cannot pan to selected feature(s)" ), tr( "Geometry is NULL" ), QgsMessageBar::WARNING );
1033  }
1034 } // panToSelected
1035 
1036 void QgsMapCanvas::keyPressEvent( QKeyEvent * e )
1037 {
1038  if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
1039  {
1040  emit keyPressed( e );
1041  return;
1042  }
1043 
1044  if ( ! mCanvasProperties->mouseButtonDown )
1045  {
1046  // Don't want to interfer with mouse events
1047 
1048  QgsRectangle currentExtent = mapSettings().visibleExtent();
1049  double dx = qAbs( currentExtent.width() / 4 );
1050  double dy = qAbs( currentExtent.height() / 4 );
1051 
1052  switch ( e->key() )
1053  {
1054  case Qt::Key_Left:
1055  QgsDebugMsg( "Pan left" );
1056  setCenter( center() - QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1057  refresh();
1058  break;
1059 
1060  case Qt::Key_Right:
1061  QgsDebugMsg( "Pan right" );
1062  setCenter( center() + QgsVector( dx, 0 ).rotateBy( rotation() * M_PI / 180.0 ) );
1063  refresh();
1064  break;
1065 
1066  case Qt::Key_Up:
1067  QgsDebugMsg( "Pan up" );
1068  setCenter( center() + QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1069  refresh();
1070  break;
1071 
1072  case Qt::Key_Down:
1073  QgsDebugMsg( "Pan down" );
1074  setCenter( center() - QgsVector( 0, dy ).rotateBy( rotation() * M_PI / 180.0 ) );
1075  refresh();
1076  break;
1077 
1078 
1079 
1080  case Qt::Key_Space:
1081  QgsDebugMsg( "Pressing pan selector" );
1082 
1083  //mCanvasProperties->dragging = true;
1084  if ( ! e->isAutoRepeat() )
1085  {
1086  QApplication::setOverrideCursor( Qt::ClosedHandCursor );
1087  mCanvasProperties->panSelectorDown = true;
1088  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1089  }
1090  break;
1091 
1092  case Qt::Key_PageUp:
1093  QgsDebugMsg( "Zoom in" );
1094  zoomIn();
1095  break;
1096 
1097  case Qt::Key_PageDown:
1098  QgsDebugMsg( "Zoom out" );
1099  zoomOut();
1100  break;
1101 
1102 #if 0
1103  case Qt::Key_P:
1104  mUseParallelRendering = !mUseParallelRendering;
1105  refresh();
1106  break;
1107 
1108  case Qt::Key_S:
1109  mDrawRenderingStats = !mDrawRenderingStats;
1110  refresh();
1111  break;
1112 #endif
1113 
1114  default:
1115  // Pass it on
1116  if ( mMapTool )
1117  {
1118  mMapTool->keyPressEvent( e );
1119  }
1120  else e->ignore();
1121 
1122  QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
1123  }
1124  }
1125 
1126  emit keyPressed( e );
1127 
1128 } //keyPressEvent()
1129 
1130 void QgsMapCanvas::keyReleaseEvent( QKeyEvent * e )
1131 {
1132  QgsDebugMsg( "keyRelease event" );
1133 
1134  switch ( e->key() )
1135  {
1136  case Qt::Key_Space:
1137  if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
1138  {
1139  QgsDebugMsg( "Releasing pan selector" );
1140  QApplication::restoreOverrideCursor();
1141  mCanvasProperties->panSelectorDown = false;
1142  panActionEnd( mCanvasProperties->mouseLastXY );
1143  }
1144  break;
1145 
1146  default:
1147  // Pass it on
1148  if ( mMapTool )
1149  {
1150  mMapTool->keyReleaseEvent( e );
1151  }
1152  else e->ignore();
1153 
1154  QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
1155  }
1156 
1157  emit keyReleased( e );
1158 
1159 } //keyReleaseEvent()
1160 
1161 
1163 {
1164  // call handler of current map tool
1165  if ( mMapTool )
1166  {
1167  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1168  mMapTool->canvasDoubleClickEvent( me.get() );
1169  }
1170 }// mouseDoubleClickEvent
1171 
1172 
1173 void QgsMapCanvas::beginZoomRect( QPoint pos )
1174 {
1175  mZoomRect.setRect( 0, 0, 0, 0 );
1176  QApplication::setOverrideCursor( mZoomCursor );
1177  mZoomDragging = true;
1178  mZoomRubberBand.reset( new QgsRubberBand( this, QgsWkbTypes::PolygonGeometry ) );
1179  QColor color( Qt::blue );
1180  color.setAlpha( 63 );
1181  mZoomRubberBand->setColor( color );
1182  mZoomRect.setTopLeft( pos );
1183 }
1184 
1185 void QgsMapCanvas::endZoomRect( QPoint pos )
1186 {
1187  mZoomDragging = false;
1188  mZoomRubberBand.reset( nullptr );
1189  QApplication::restoreOverrideCursor();
1190 
1191  // store the rectangle
1192  mZoomRect.setRight( pos.x() );
1193  mZoomRect.setBottom( pos.y() );
1194 
1195  if ( mZoomRect.width() < 5 && mZoomRect.height() < 5 )
1196  {
1197  //probably a mistake - would result in huge zoom!
1198  return;
1199  }
1200 
1201  //account for bottom right -> top left dragging
1202  mZoomRect = mZoomRect.normalized();
1203 
1204  // set center and zoom
1205  const QSize& zoomRectSize = mZoomRect.size();
1206  const QSize& canvasSize = mSettings.outputSize();
1207  double sfx = ( double )zoomRectSize.width() / canvasSize.width();
1208  double sfy = ( double )zoomRectSize.height() / canvasSize.height();
1209  double sf = qMax( sfx, sfy );
1210 
1211  QgsPoint c = mSettings.mapToPixel().toMapCoordinates( mZoomRect.center() );
1212 
1213  zoomByFactor( sf, &c );
1214  refresh();
1215 }
1216 
1217 void QgsMapCanvas::mousePressEvent( QMouseEvent* e )
1218 {
1219  //use middle mouse button for panning, map tools won't receive any events in that case
1220  if ( e->button() == Qt::MidButton )
1221  {
1222  mCanvasProperties->panSelectorDown = true;
1223  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1224  }
1225  else
1226  {
1227  // call handler of current map tool
1228  if ( mMapTool )
1229  {
1230  if ( mMapTool->flags() & QgsMapTool::AllowZoomRect && e->button() == Qt::LeftButton
1231  && e->modifiers() & Qt::ShiftModifier )
1232  {
1233  beginZoomRect( e->pos() );
1234  return;
1235  }
1236  else
1237  {
1238  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1239  mMapTool->canvasPressEvent( me.get() );
1240  }
1241  }
1242  }
1243 
1244  if ( mCanvasProperties->panSelectorDown )
1245  {
1246  return;
1247  }
1248 
1249  mCanvasProperties->mouseButtonDown = true;
1250  mCanvasProperties->rubberStartPoint = e->pos();
1251 
1252 } // mousePressEvent
1253 
1254 
1255 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent* e )
1256 {
1257  //use middle mouse button for panning, map tools won't receive any events in that case
1258  if ( e->button() == Qt::MidButton )
1259  {
1260  mCanvasProperties->panSelectorDown = false;
1261  panActionEnd( mCanvasProperties->mouseLastXY );
1262  }
1263  else
1264  {
1265  if ( mZoomDragging && e->button() == Qt::LeftButton )
1266  {
1267  endZoomRect( e->pos() );
1268  return;
1269  }
1270 
1271  // call handler of current map tool
1272  if ( mMapTool )
1273  {
1274  // right button was pressed in zoom tool? return to previous non zoom tool
1275  if ( e->button() == Qt::RightButton && mMapTool->flags() & QgsMapTool::Transient )
1276  {
1277  QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
1278  QString( mLastNonZoomMapTool ? "not null." : "null." ) );
1279 
1280  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1281 
1282  // change to older non-zoom tool
1283  if ( mLastNonZoomMapTool
1284  && ( !( mLastNonZoomMapTool->flags() & QgsMapTool::EditTool )
1285  || ( vlayer && vlayer->isEditable() ) ) )
1286  {
1287  QgsMapTool* t = mLastNonZoomMapTool;
1288  mLastNonZoomMapTool = nullptr;
1289  setMapTool( t );
1290  }
1291  return;
1292  }
1293  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1294  mMapTool->canvasReleaseEvent( me.get() );
1295  }
1296  }
1297 
1298 
1299  mCanvasProperties->mouseButtonDown = false;
1300 
1301  if ( mCanvasProperties->panSelectorDown )
1302  return;
1303 
1304 } // mouseReleaseEvent
1305 
1306 void QgsMapCanvas::resizeEvent( QResizeEvent * e )
1307 {
1308  QGraphicsView::resizeEvent( e );
1309  mResizeTimer->start( 500 );
1310 
1311  QSize lastSize = viewport()->size();
1312 
1313  mSettings.setOutputSize( lastSize );
1314 
1315  mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1316 
1317  moveCanvasContents( true );
1318 
1319  // notify canvas items of change
1321 
1322  updateScale();
1323 
1324  //refresh();
1325 
1326  emit extentsChanged();
1327 }
1328 
1329 void QgsMapCanvas::paintEvent( QPaintEvent *e )
1330 {
1331  // no custom event handling anymore
1332 
1333  QGraphicsView::paintEvent( e );
1334 } // paintEvent
1335 
1337 {
1338  QList<QGraphicsItem*> list = mScene->items();
1339  QList<QGraphicsItem*>::iterator it = list.begin();
1340  while ( it != list.end() )
1341  {
1342  QgsMapCanvasItem* item = dynamic_cast<QgsMapCanvasItem *>( *it );
1343 
1344  if ( item )
1345  {
1346  item->updatePosition();
1347  }
1348 
1349  ++it;
1350  }
1351 }
1352 
1353 
1354 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
1355 {
1356  // Zoom the map canvas in response to a mouse wheel event. Moving the
1357  // wheel forward (away) from the user zooms in
1358 
1359  QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
1360 
1361  if ( mMapTool )
1362  {
1363  mMapTool->wheelEvent( e );
1364  if ( e->isAccepted() )
1365  return;
1366  }
1367 
1368  double zoomFactor = mWheelZoomFactor;
1369 
1370  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1371  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * qAbs( e->angleDelta().y() );
1372 
1373  if ( e->modifiers() & Qt::ControlModifier )
1374  {
1375  //holding ctrl while wheel zooming results in a finer zoom
1376  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1377  }
1378 
1379  double signedWheelFactor = e->angleDelta().y() > 0 ? 1 / zoomFactor : zoomFactor;
1380 
1381  // zoom map to mouse cursor by scaling
1382  QgsPoint oldCenter = center();
1383  QgsPoint mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
1384  QgsPoint newCenter( mousePos.x() + (( oldCenter.x() - mousePos.x() ) * signedWheelFactor ),
1385  mousePos.y() + (( oldCenter.y() - mousePos.y() ) * signedWheelFactor ) );
1386 
1387  zoomByFactor( signedWheelFactor, &newCenter );
1388 }
1389 
1390 void QgsMapCanvas::setWheelFactor( double factor )
1391 {
1392  mWheelZoomFactor = factor;
1393 }
1394 
1396 {
1397  // magnification is alreday handled in zoomByFactor
1398  zoomByFactor( 1 / mWheelZoomFactor );
1399 }
1400 
1402 {
1403  // magnification is alreday handled in zoomByFactor
1404  zoomByFactor( mWheelZoomFactor );
1405 }
1406 
1407 void QgsMapCanvas::zoomScale( double newScale )
1408 {
1409  zoomByFactor( newScale / scale() );
1410 }
1411 
1412 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
1413 {
1414  double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1415 
1416  if ( mScaleLocked )
1417  {
1419  }
1420  else
1421  {
1422  // transform the mouse pos to map coordinates
1425  r.scale( scaleFactor, &center );
1426  setExtent( r, true );
1427  refresh();
1428  }
1429 }
1430 
1431 void QgsMapCanvas::setScaleLocked( bool isLocked )
1432 {
1433  mScaleLocked = isLocked;
1434 }
1435 
1436 void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
1437 {
1438  mCanvasProperties->mouseLastXY = e->pos();
1439 
1440  if ( mCanvasProperties->panSelectorDown )
1441  {
1442  panAction( e );
1443  }
1444  else if ( mZoomDragging )
1445  {
1446  mZoomRect.setBottomRight( e->pos() );
1447  mZoomRubberBand->setToCanvasRectangle( mZoomRect );
1448  mZoomRubberBand->show();
1449  }
1450  else
1451  {
1452  // call handler of current map tool
1453  if ( mMapTool )
1454  {
1455  std::unique_ptr<QgsMapMouseEvent> me( new QgsMapMouseEvent( this, e ) );
1456  mMapTool->canvasMoveEvent( me.get() );
1457  }
1458  }
1459 
1460  // show x y on status bar
1461  QPoint xy = e->pos();
1463  emit xyCoordinates( coord );
1464 } // mouseMoveEvent
1465 
1466 
1467 
1470 {
1471  if ( !tool )
1472  return;
1473 
1474  if ( mMapTool )
1475  {
1476  disconnect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1477  mMapTool->deactivate();
1478  }
1479 
1480  if (( tool->flags() & QgsMapTool::Transient )
1481  && mMapTool && !( mMapTool->flags() & QgsMapTool::Transient ) )
1482  {
1483  // if zoom or pan tool will be active, save old tool
1484  // to bring it back on right click
1485  // (but only if it wasn't also zoom or pan tool)
1486  mLastNonZoomMapTool = mMapTool;
1487  }
1488  else
1489  {
1490  mLastNonZoomMapTool = nullptr;
1491  }
1492 
1493  QgsMapTool* oldTool = mMapTool;
1494 
1495  // set new map tool and activate it
1496  mMapTool = tool;
1497  if ( mMapTool )
1498  {
1499  connect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1500  mMapTool->activate();
1501  }
1502 
1503  emit mapToolSet( mMapTool );
1504  emit mapToolSet( mMapTool, oldTool );
1505 } // setMapTool
1506 
1508 {
1509  if ( mMapTool && mMapTool == tool )
1510  {
1511  mMapTool->deactivate();
1512  mMapTool = nullptr;
1513  emit mapToolSet( nullptr );
1514  emit mapToolSet( nullptr, mMapTool );
1515  setCursor( Qt::ArrowCursor );
1516  }
1517 
1518  if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1519  {
1520  mLastNonZoomMapTool = nullptr;
1521  }
1522 }
1523 
1525 void QgsMapCanvas::setCanvasColor( const QColor & theColor )
1526 {
1527  // background of map's pixmap
1528  mSettings.setBackgroundColor( theColor );
1529 
1530  // background of the QGraphicsView
1531  QBrush bgBrush( theColor );
1532  setBackgroundBrush( bgBrush );
1533 #if 0
1534  QPalette palette;
1535  palette.setColor( backgroundRole(), theColor );
1536  setPalette( palette );
1537 #endif
1538 
1539  // background of QGraphicsScene
1540  mScene->setBackgroundBrush( bgBrush );
1541 } // setBackgroundColor
1542 
1544 {
1545  return mScene->backgroundBrush().color();
1546 }
1547 
1548 void QgsMapCanvas::setSelectionColor( const QColor& color )
1549 {
1550  mSettings.setSelectionColor( color );
1551 }
1552 
1554 {
1555  return mapSettings().layers().size();
1556 } // layerCount
1557 
1558 
1559 QList<QgsMapLayer*> QgsMapCanvas::layers() const
1560 {
1561  return mapSettings().layers();
1562 }
1563 
1564 
1566 {
1567  // called when a layer has changed visibility setting
1568 
1569  refresh();
1570 
1571 } // layerStateChange
1572 
1574 {
1575  // called when a layer's CRS has been changed
1576  QObject *theSender = sender();
1577  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( theSender );
1578  QString destAuthId = mSettings.destinationCrs().authid();
1579  getDatumTransformInfo( layer, layer->crs().authid(), destAuthId );
1580 
1581 } // layerCrsChange
1582 
1583 
1584 void QgsMapCanvas::freeze( bool frz )
1585 {
1586  mFrozen = frz;
1587 } // freeze
1588 
1590 {
1591  return mFrozen;
1592 } // freeze
1593 
1594 
1596 {
1597  return mapSettings().mapUnitsPerPixel();
1598 } // mapUnitsPerPixel
1599 
1600 
1602 {
1603  if ( mSettings.mapUnits() == u )
1604  return;
1605 
1606  QgsDebugMsg( "Setting map units to " + QString::number( static_cast<int>( u ) ) );
1607  mSettings.setMapUnits( u );
1608 
1609  updateScale();
1610 
1611  refresh(); // this will force the scale bar to be updated
1612 
1613  emit mapUnitsChanged();
1614 }
1615 
1616 
1618 {
1619  return mapSettings().mapUnits();
1620 }
1621 
1622 QMap<QString, QString> QgsMapCanvas::layerStyleOverrides() const
1623 {
1624  return mSettings.layerStyleOverrides();
1625 }
1626 
1627 void QgsMapCanvas::setLayerStyleOverrides( const QMap<QString, QString>& overrides )
1628 {
1629  if ( overrides == mSettings.layerStyleOverrides() )
1630  return;
1631 
1632  mSettings.setLayerStyleOverrides( overrides );
1634 }
1635 
1636 
1637 void QgsMapCanvas::setRenderFlag( bool theFlag )
1638 {
1639  mRenderFlag = theFlag;
1640 
1641  if ( mRenderFlag )
1642  {
1643  refresh();
1644  }
1645  else
1646  stopRendering();
1647 }
1648 
1649 #if 0
1650 void QgsMapCanvas::connectNotify( const char * signal )
1651 {
1652  Q_UNUSED( signal );
1653  QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
1654 } //connectNotify
1655 #endif
1656 
1658 {
1659  if ( !mSettings.hasCrsTransformEnabled() )
1660  return;
1661 
1662  QString destAuthId = mSettings.destinationCrs().authid();
1663  Q_FOREACH ( QgsMapLayer* layer, mSettings.layers() )
1664  {
1665  QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
1666  if ( vl && vl->geometryType() == QgsWkbTypes::NullGeometry )
1667  continue;
1668 
1669  // if there are more options, ask the user which datum transform to use
1670  if ( !mSettings.datumTransformStore().hasEntryForLayer( layer ) )
1671  getDatumTransformInfo( layer, layer->crs().authid(), destAuthId );
1672  }
1673 }
1674 
1675 void QgsMapCanvas::layerRepaintRequested( bool deferred )
1676 {
1677  if ( !deferred )
1678  refresh();
1679 }
1680 
1681 void QgsMapCanvas::autoRefreshTriggered()
1682 {
1683  if ( mJob )
1684  {
1685  // canvas is currently being redrawn, so we skip this auto refresh
1686  // otherwise we could get stuck in the situation where an auto refresh is triggered
1687  // too often to allow the canvas to ever finish rendering
1688  return;
1689  }
1690 
1691  refresh();
1692 }
1693 
1694 void QgsMapCanvas::updateAutoRefreshTimer()
1695 {
1696  // min auto refresh interval stores the smallest interval between layer auto refreshes. We automatically
1697  // trigger a map refresh on this minimum interval
1698  int minAutoRefreshInterval = -1;
1699  Q_FOREACH ( QgsMapLayer* layer, mSettings.layers() )
1700  {
1701  if ( layer->hasAutoRefreshEnabled() && layer->autoRefreshInterval() > 0 )
1702  minAutoRefreshInterval = minAutoRefreshInterval > 0 ? qMin( layer->autoRefreshInterval(), minAutoRefreshInterval ) : layer->autoRefreshInterval();
1703  }
1704 
1705  if ( minAutoRefreshInterval > 0 )
1706  {
1707  mAutoRefreshTimer.setInterval( minAutoRefreshInterval );
1708  mAutoRefreshTimer.start();
1709  }
1710  else
1711  {
1712  mAutoRefreshTimer.stop();
1713  }
1714 }
1715 
1717 {
1718  return mMapTool;
1719 }
1720 
1721 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
1722 {
1723  // move map image and other items to standard position
1724  moveCanvasContents( true ); // true means reset
1725 
1726  // use start and end box points to calculate the extent
1727  QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
1728  QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );
1729 
1730  // modify the center
1731  double dx = end.x() - start.x();
1732  double dy = end.y() - start.y();
1733  QgsPoint c = center();
1734  c.set( c.x() - dx, c.y() - dy );
1735  setCenter( c );
1736 
1737  refresh();
1738 }
1739 
1740 void QgsMapCanvas::panAction( QMouseEvent * e )
1741 {
1742  Q_UNUSED( e );
1743 
1744  // move all map canvas items
1746 }
1747 
1749 {
1750  QPoint pnt( 0, 0 );
1751  if ( !reset )
1752  pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
1753 
1754  setSceneRect( -pnt.x(), -pnt.y(), viewport()->size().width(), viewport()->size().height() );
1755 }
1756 
1758 {
1759  return mCanvasProperties->mouseLastXY;
1760 }
1761 
1762 void QgsMapCanvas::setPreviewModeEnabled( bool previewEnabled )
1763 {
1764  if ( !mPreviewEffect )
1765  {
1766  return;
1767  }
1768 
1769  mPreviewEffect->setEnabled( previewEnabled );
1770 }
1771 
1773 {
1774  if ( !mPreviewEffect )
1775  {
1776  return false;
1777  }
1778 
1779  return mPreviewEffect->isEnabled();
1780 }
1781 
1783 {
1784  if ( !mPreviewEffect )
1785  {
1786  return;
1787  }
1788 
1789  mPreviewEffect->setMode( mode );
1790 }
1791 
1793 {
1794  if ( !mPreviewEffect )
1795  {
1797  }
1798 
1799  return mPreviewEffect->mode();
1800 }
1801 
1803 {
1804  if ( !mSnappingUtils )
1805  {
1806  // associate a dummy instance, but better than null pointer
1807  QgsMapCanvas* c = const_cast<QgsMapCanvas*>( this );
1808  c->mSnappingUtils = new QgsMapCanvasSnappingUtils( c, c );
1809  }
1810  return mSnappingUtils;
1811 }
1812 
1814 {
1815  mSnappingUtils = utils;
1816 }
1817 
1818 void QgsMapCanvas::readProject( const QDomDocument & doc )
1819 {
1820  QDomNodeList nodes = doc.elementsByTagName( QStringLiteral( "mapcanvas" ) );
1821  if ( nodes.count() )
1822  {
1823  QDomNode node = nodes.item( 0 );
1824 
1825  QgsMapSettings tmpSettings;
1826  tmpSettings.readXml( node );
1827  setMapUnits( tmpSettings.mapUnits() );
1829  setDestinationCrs( tmpSettings.destinationCrs() );
1830  setExtent( tmpSettings.extent() );
1831  setRotation( tmpSettings.rotation() );
1832  mSettings.datumTransformStore() = tmpSettings.datumTransformStore();
1834 
1835  clearExtentHistory(); // clear the extent history on project load
1836  }
1837  else
1838  {
1839  QgsDebugMsg( "Couldn't read mapcanvas information from project" );
1840  }
1841 }
1842 
1843 void QgsMapCanvas::writeProject( QDomDocument & doc )
1844 {
1845  // create node "mapcanvas" and call mMapRenderer->writeXml()
1846 
1847  QDomNodeList nl = doc.elementsByTagName( QStringLiteral( "qgis" ) );
1848  if ( !nl.count() )
1849  {
1850  QgsDebugMsg( "Unable to find qgis element in project file" );
1851  return;
1852  }
1853  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element ok
1854 
1855  QDomElement mapcanvasNode = doc.createElement( QStringLiteral( "mapcanvas" ) );
1856  qgisNode.appendChild( mapcanvasNode );
1857 
1858  mSettings.writeXml( mapcanvasNode, doc );
1859  // TODO: store only units, extent, projections, dest CRS
1860 }
1861 
1863 void QgsMapCanvas::getDatumTransformInfo( const QgsMapLayer* ml, const QString& srcAuthId, const QString& destAuthId )
1864 {
1865  if ( !ml )
1866  {
1867  return;
1868  }
1869 
1870  //check if default datum transformation available
1871  QSettings s;
1872  QString settingsString = "/Projections/" + srcAuthId + "//" + destAuthId;
1873  QVariant defaultSrcTransform = s.value( settingsString + "_srcTransform" );
1874  QVariant defaultDestTransform = s.value( settingsString + "_destTransform" );
1875  if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
1876  {
1877  mSettings.datumTransformStore().addEntry( ml->id(), srcAuthId, destAuthId, defaultSrcTransform.toInt(), defaultDestTransform.toInt() );
1878  return;
1879  }
1880 
1883 
1884  if ( !s.value( QStringLiteral( "/Projections/showDatumTransformDialog" ), false ).toBool() )
1885  {
1886  // just use the default transform
1887  mSettings.datumTransformStore().addEntry( ml->id(), srcAuthId, destAuthId, -1, -1 );
1888  return;
1889  }
1890 
1891  //get list of datum transforms
1892  QList< QList< int > > dt = QgsCoordinateTransform::datumTransformations( srcCRS, destCRS );
1893  if ( dt.size() < 2 )
1894  {
1895  return;
1896  }
1897 
1898  //if several possibilities: present dialog
1899  QgsDatumTransformDialog d( ml->name(), dt );
1900  d.setDatumTransformInfo( srcCRS.authid(), destCRS.authid() );
1901  if ( d.exec() == QDialog::Accepted )
1902  {
1903  int srcTransform = -1;
1904  int destTransform = -1;
1905  QList<int> t = d.selectedDatumTransform();
1906  if ( !t.isEmpty() )
1907  {
1908  srcTransform = t.at( 0 );
1909  }
1910  if ( t.size() > 1 )
1911  {
1912  destTransform = t.at( 1 );
1913  }
1914  mSettings.datumTransformStore().addEntry( ml->id(), srcAuthId, destAuthId, srcTransform, destTransform );
1915  if ( d.rememberSelection() )
1916  {
1917  s.setValue( settingsString + "_srcTransform", srcTransform );
1918  s.setValue( settingsString + "_destTransform", destTransform );
1919  }
1920  }
1921  else
1922  {
1923  mSettings.datumTransformStore().addEntry( ml->id(), srcAuthId, destAuthId, -1, -1 );
1924  }
1925 }
1926 
1927 void QgsMapCanvas::zoomByFactor( double scaleFactor, const QgsPoint* center )
1928 {
1929  if ( mScaleLocked )
1930  {
1931  // zoom map to mouse cursor by magnifying
1933  }
1934  else
1935  {
1937  r.scale( scaleFactor, center );
1938  setExtent( r, true );
1939  refresh();
1940  }
1941 }
1942 
1944 {
1945  // Find out which layer it was that sent the signal.
1946  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
1947  emit selectionChanged( layer );
1948  refresh();
1949 }
1950 
1951 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent * e )
1952 {
1953  // By default graphics view delegates the drag events to graphics items.
1954  // But we do not want that and by ignoring the drag enter we let the
1955  // parent (e.g. QgisApp) to handle drops of map layers etc.
1956  e->ignore();
1957 }
1958 
1959 void QgsMapCanvas::mapToolDestroyed()
1960 {
1961  QgsDebugMsg( "maptool destroyed" );
1962  mMapTool = nullptr;
1963 }
1964 
1965 bool QgsMapCanvas::event( QEvent * e )
1966 {
1967  if ( !QTouchDevice::devices().empty() )
1968  {
1969  if ( e->type() == QEvent::Gesture )
1970  {
1971  // call handler of current map tool
1972  if ( mMapTool )
1973  {
1974  return mMapTool->gestureEvent( static_cast<QGestureEvent*>( e ) );
1975  }
1976  }
1977  }
1978 
1979  // pass other events to base class
1980  return QGraphicsView::event( e );
1981 }
1982 
1984 {
1985  // reload all layers in canvas
1986  for ( int i = 0; i < layerCount(); i++ )
1987  {
1988  QgsMapLayer *l = layer( i );
1989  if ( l )
1990  l->reload();
1991  }
1992 
1993  // clear the cache
1994  clearCache();
1995 
1996  // and then refresh
1997  refresh();
1998 }
1999 
2001 {
2002  mSettings.setSegmentationTolerance( tolerance );
2003 }
2004 
2006 {
2007  mSettings.setSegmentationToleranceType( type );
2008 }
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
void setRequestedGeometryCacheForLayers(const QStringList &layerIds)
Set which vector layers should be cached while rendering.
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:57
void setParallelRenderingEnabled(bool enabled)
Set whether the layers are rendered in parallel or sequentially.
static unsigned index
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
QPoint mouseLastXY
Last seen point of the mouse.
A rectangle specified with double values.
Definition: qgsrectangle.h:36
Base class for all map layer types.
Definition: qgsmaplayer.h:52
void setExtent(const QgsRectangle &rect, bool magnified=true)
Set coordinates of the rectangle which should be rendered.
double y
Definition: qgspoint.h:148
Job implementation that renders everything sequentially using a custom painter.
std::unique_ptr< CanvasProperties > mCanvasProperties
Handle pattern for implementation object.
Definition: qgsmapcanvas.h:597
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.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:222
virtual void canvasMoveEvent(QgsMapMouseEvent *e)
Mouse move event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:144
int mapUpdateInterval() const
Find out how often map preview should be updated while it is being rendered (in milliseconds) ...
void zoomToNextExtent()
Zoom to the next extent (view)
void writeXml(QDomNode &theNode, QDomDocument &theDoc)
void zoomWithCenter(int x, int y, bool zoomIn)
Zooms in/out with a given center.
void freeze(bool frz=true)
Freeze/thaw the map canvas.
void setCanvasColor(const QColor &_newVal)
Write property of QColor bgColor.
void setMinimal()
Set a rectangle so that min corner is at max and max corner is at min.
void setSegmentationToleranceType(QgsAbstractGeometry::SegmentationToleranceType type)
Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
static QList< QList< int > > datumTransformations(const QgsCoordinateReferenceSystem &srcCRS, const QgsCoordinateReferenceSystem &destinationCrs)
Returns list of datum transformations for the given src and dest CRS.
QList< QgsMapLayer * > layers() const
return list of layers within map canvas.
const char * zoom_in[]
Bitmap cursors for map operations.
Definition: qgscursors.cpp:21
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)
Setter for stored overrides of styles for layers.
double magnificationFactor() const
Return the magnification factor.
double rotation() const
Return the rotation of the resulting map image Units are clockwise degrees.
void setExpressionContext(const QgsExpressionContext &context)
Sets the expression context.
void clearExtentHistory()
bool event(QEvent *e) override
Overridden standard event to be gestures aware.
bool mouseButtonDown
Flag to indicate status of mouse button.
void wheelEvent(QWheelEvent *e) override
Overridden mouse wheel event.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeature.h:355
void stopRendering()
stop rendering (if there is any right now)
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent) const
transform bounding box from layer&#39;s CRS to output CRS
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.
int selectedFeatureCount() const
The number of features that are selected in this layer.
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:299
Allow zooming by rectangle (by holding shift and dragging) while the tool is active.
Definition: qgsmaptool.h:64
Whether to make extra effort to update map image with partially rendered layers (better for interacti...
void scale(double scaleFactor, const QgsPoint *c=nullptr)
Scale the rectangle around its center point.
An abstract class for items that can be placed on the map canvas.
bool hasCrsTransformEnabled()
A simple helper method to find out if on the fly projections are enabled or not.
void setCurrentLayer(QgsMapLayer *layer)
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
QgsPoint toMapPoint(double x, double y) const
int layerCount() const
return number of layers on the map
const QgsDatumTransformStore & datumTransformStore() const
Errors errors() const
List of errors that happened during the rendering job - available when the rendering has been finishe...
void moveCanvasContents(bool reset=false)
called when panning is in action, reset indicates end of panning
void crsChanged()
Emit a signal that layer&#39;s CRS has been reset.
A QgsMapMouseEvent is the result of a user interaction with the mouse on a QgsMapCanvas.
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
QgsPoint toMapCoordinates(int x, int y) const
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:79
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:136
void mousePressEvent(QMouseEvent *e) override
Overridden mouse press event.
virtual Flags flags() const
Returns the flags for the map tool.
Definition: qgsmaptool.h:71
virtual bool isEditable() const override
Returns true if the provider is in editing mode.
void setSegmentationTolerance(double tolerance)
Sets the segmentation tolerance applied when rendering curved geometries.
virtual QImage renderedImage()=0
Get a preview/resulting image.
int renderingTime() const
Find out how long it took to finish the job (in milliseconds)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:72
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:198
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:154
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:38
void setFlag(Flag flag, bool on=true)
Enable or disable a particular flag (other flags are not affected)
void updateScale()
Emits signal scaleChanged to update scale in main window.
QgsUnitTypes::DistanceUnit mapUnits() const
Get units of map&#39;s geographical coordinates - used for scale calculation.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
The QgsMapSettings class contains configuration for rendering of the map.
void resizeEvent(QResizeEvent *e) override
Overridden resize event.
void setDatumTransformInfo(const QString &srcCRSauthId, const QString &destCRSauthId)
Deprecated to be deleted, stuff from here should be moved elsewhere.
void hasCrsTransformEnabledChanged(bool flag)
Emitted when on-the-fly projection has been turned on/off.
void setMapTool(QgsMapTool *mapTool)
Sets the map tool currently being used on the canvas.
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:82
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:34
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:174
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.
Map tool is an edit tool, which can only be used when layer is editable.
Definition: qgsmaptool.h:63
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 saveAsImage(const QString &theFileName, QPixmap *QPixmap=nullptr, const QString &="PNG")
Save the convtents of the map canvas to disk as an image.
virtual void start() override
Start the rendering job and immediately return.
void addEntry(const QString &layerId, const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform, int destDatumTransform)
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
double scale()
Get the last reported scale of the canvas.
void rotationChanged(double)
Emitted when the rotation of the map changes.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
void setMagnificationFactor(double factor)
Set the magnification factor.
void zoomNextStatusChanged(bool)
Emitted when zoom next status changed.
bool isEmpty() const
test if rectangle is empty.
void setRotation(double degrees)
Set the rotation of the resulting map image Units are clockwise degrees.
void setMapUnits(QgsUnitTypes::DistanceUnit mapUnits)
Set map units (needed by project properties dialog)
void clearCache()
Make sure to remove any rendered images from cache (does nothing if cache is not enabled) ...
QgsMapCanvas(QWidget *parent=nullptr)
Constructor.
void layerCrsChange()
This slot is connected to the layer&#39;s CRS change.
A class for drawing transient features (e.g.
Definition: qgsrubberband.h:33
double scale() const
Return the calculated scale of the map.
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
Width of the rectangle.
Definition: qgsrectangle.h:212
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:186
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const
Query the layer for features specified in request.
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.
Enable anti-aliasing for map rendering.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void getDatumTransformInfo(const QgsMapLayer *ml, const QString &srcAuthId, const QString &destAuthId)
ask user about datum transformation
void panToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Centers canvas extent to feature ids.
#define M_PI
void enableMapTileRendering(bool theFlag)
sets map tile rendering flag
void mouseDoubleClickEvent(QMouseEvent *e) override
Overridden mouse double click event.
static void logMessage(const QString &message, const QString &tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
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.
QList< int > QgsAttributeList
void setWheelFactor(double factor)
set wheel zoom factor (should be greater than 1)
QgsCoordinateReferenceSystem crs() const
Returns the layer&#39;s spatial reference system.
void messageEmitted(const QString &title, const QString &message, QgsMessageBar::MessageLevel=QgsMessageBar::INFO)
emit a message (usually to be displayed in a message bar)
void destinationCrsChanged()
Emitted when map CRS has changed.
void updateDatumTransformEntries()
Make sure the datum transform store is properly populated.
void setRenderFlag(bool theFlag)
Whether to suppress rendering or not.
void readXml(QDomNode &theNode)
bool hasValidSettings() const
Check whether the map settings are valid and can be used for rendering.
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:98
Single scope for storing variables and functions for use within a QgsExpressionContext.
QgsGeometry geometry() const
Returns the geometry associated with this feature.
Definition: qgsfeature.cpp:113
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:164
void set(double x, double y)
Sets the x and y value of the point.
Definition: qgspoint.h:207
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.
A class to represent a point.
Definition: qgspoint.h:143
const QgsMapToPixel & mapToPixel() const
void keyPressed(QKeyEvent *e)
Emit key press event.
void currentLayerChanged(QgsMapLayer *layer)
Emitted when the current layer is changed.
constexpr double CANVAS_MAGNIFICATION_MAX
Maximum magnification level allowed in map canvases.
Definition: qgisgui.h:66
void zoomOut()
Zoom out with fixed factor.
Enable drawing of vertex markers for layers in editing mode.
void zoomToPreviousExtent()
Zoom to the previous extent (view)
void xyCoordinates(const QgsPoint &p)
Emits current mouse position.
bool isDrawing()
Find out whether rendering is in progress.
void zoomToSelected(QgsVectorLayer *layer=nullptr)
Zoom to the extent of the selected features of current (vector) layer.
A class to represent a vector.
Definition: qgspoint.h:33
PreviewMode mode() const
Returns the mode used for the preview effect.
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.
QPoint mouseLastXY()
returns last position of mouse cursor
double magnificationFactor() const
Returns the magnification factor.
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
QMap< QString, QString > layerStyleOverrides() const
Getter for stored overrides of styles for layers.
void mouseMoveEvent(QMouseEvent *e) override
Overridden mouse move event.
void keyReleaseEvent(QKeyEvent *e) override
Overridden key release event.
void selectionChanged(QgsMapLayer *layer)
Emitted when selection in any layer gets changed.
virtual void keyPressEvent(QKeyEvent *e)
Key event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:169
DistanceUnit
Units of distance.
Definition: qgsunittypes.h:43
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.
Abstract base class for all map tools.
Definition: qgsmaptool.h:49
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.
QgsUnitTypes::DistanceUnit mapUnits() const
Get the current canvas map units.
void setBackgroundColor(const QColor &color)
Set the background color of the map.
void mouseReleaseEvent(QMouseEvent *e) override
Overridden mouse release event.
QMap< QString, QString > layerStyleOverrides() const
Get map of map layer style overrides (key: layer ID, value: style name) where a different style shoul...
void zoomToFeatureIds(QgsVectorLayer *layer, const QgsFeatureIds &ids)
Set canvas extent to the bounding box of a set of features.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
static QgsCoordinateReferenceSystem fromOgcWmsCrs(const QString &ogcCrs)
Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
virtual bool gestureEvent(QGestureEvent *e)
gesture event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:179
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:149
bool hasEntryForLayer(QgsMapLayer *layer) const
void dragEnterEvent(QDragEnterEvent *e) override
Overridden drag enter event.
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)
Set list of layers that should be shown in the canvas.
QgsRectangle fullExtent() const
returns current extent of layer set
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:355
void zoomToFullExtent()
Zoom to the full extent of all layers.
QgsRectangle boundingBox() const
Returns the bounding box of the geometry.
This class represents a coordinate reference system (CRS).
QgsRectangle fullExtent() const
Returns the combined extent for all layers on the map canvas.
This class has all the configuration of snapping and can return answers to snapping queries...
const QgsLabelingResults * labelingResults() const
Get access to the labeling results (may be null)
bool isNull() const
test if the rectangle is null (all coordinates zero or after call to setMinimal()).
void refreshAllLayers()
Reload all layers, clear the cache and refresh the canvas.
void zoomScale(double scale)
Zoom 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
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:197
void setLayers(const QList< QgsMapLayer *> &layers)
Set list of layers for map rendering.
bool isFrozen()
Accessor for frozen status of canvas.
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
void scaleChanged(double)
Emitted when the scale of the map changes.
void setSegmentationToleranceType(QgsAbstractGeometry::SegmentationToleranceType type)
Sets segmentation tolerance type (maximum angle or maximum difference between curve and approximation...
void setCenter(const QgsPoint &center)
Set the center of the map canvas, in geographical coordinates.
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
void enableAntiAliasing(bool theFlag)
used to determine if anti-aliasing is enabled or not
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:202
void setSelectionColor(const QColor &color)
Set color of selected vector features.
QString name
Read property of QString layerName.
Definition: qgsmaplayer.h:56
void paintEvent(QPaintEvent *e) override
Overridden paint event.
void layerStateChange()
This slot is connected to the visibility change of one or more layers.
Enable vector simplification and other rendering optimizations.
void setScaleLocked(bool isLocked)
Lock the scale, so zooming can be performed using magnication.
Class that stores computed placement from labeling engine.
This class is responsible for keeping cache of rendered images resulting from a map rendering job...
bool testFlag(Flag flag) const
Check whether a particular flag is enabled.
Custom exception class for Coordinate Reference System related exceptions.
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 autoRefreshIntervalChanged(int interval)
Emitted when the auto refresh interval changes.
void zoomIn()
Zoom in with fixed factor.
virtual void waitForFinished() override
Block until the job has finished.
Represents a vector layer which manages a vector based data sets.
virtual void updatePosition()
called on changed extent or resize event to update position of the item
bool isParallelRenderingEnabled() const
Check whether the layers are rendered in parallel or sequentially.
QgsPoint center() const
Get map center, in geographical coordinates.
void extentsChanged()
Emitted when the extents of the map change.
QgsAbstractGeometry * geometry() const
Returns the underlying geometry store.
QSize outputSize() const
Return the size of the resulting map image.
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 zoomByFactor(double scaleFactor, const QgsPoint *center=nullptr)
Zoom with the factor supplied.
void setMapUnits(QgsUnitTypes::DistanceUnit u)
Set units of map&#39;s geographical coordinates - used for scale calculation.
constexpr double CANVAS_MAGNIFICATION_MIN
Minimum magnification level allowed in map canvases.
Definition: qgisgui.h:58
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:217
void setMagnificationFactor(double factor)
Sets the factor of magnification to apply to the map canvas.
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
void panActionEnd(QPoint releasePoint)
Ends pan action and redraws the canvas.
void mapUnitsChanged()
Emitted when map units are changed.
bool previewModeEnabled() const
Returns whether a preview mode is enabled for the map canvas.
void layersChanged()
Emitted when a new set of layers has been received.
virtual bool usedCachedLabels() const =0
Returns true if the render job was able to use a cached labeling solution.
void mapToolSet(QgsMapTool *tool)
Emit map tool changed event.
double x
Definition: qgspoint.h:147
virtual void canvasReleaseEvent(QgsMapMouseEvent *e)
Mouse release event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:159