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