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