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