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