QGIS API Documentation  2.3.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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"
47 #include "qgsmaplayer.h"
48 #include "qgsmaplayerregistry.h"
49 #include "qgsmaptoolpan.h"
50 #include "qgsmaptoolzoom.h"
51 #include "qgsmaptopixel.h"
52 #include "qgsmapoverviewcanvas.h"
53 #include "qgsmaprenderer.h"
54 #include "qgsmaprenderercache.h"
55 #include "qgsmaprendererjob.h"
56 #include "qgsmessagelog.h"
57 #include "qgsmessageviewer.h"
58 #include "qgspallabeling.h"
59 #include "qgsproject.h"
60 #include "qgsrubberband.h"
61 #include "qgsvectorlayer.h"
62 #include <math.h>
63 
64 
67 {
68  public:
69 
71 
74 
76  QPoint mouseLastXY;
77 
80 
83 
84 };
85 
86 
87 
89  : QObject( canvas )
90  , mCanvas( canvas )
91  , mRenderer( renderer )
92 {
93  connect( mCanvas, SIGNAL( extentsChanged() ), this, SLOT( onExtentC2R() ) );
94  connect( mRenderer, SIGNAL( extentsChanged() ), this, SLOT( onExtentR2C() ) );
95 
96  connect( mCanvas, SIGNAL( mapUnitsChanged() ), this, SLOT( onMapUnitsC2R() ) );
97  connect( mRenderer, SIGNAL( mapUnitsChanged() ), this, SLOT( onMapUnitsR2C() ) );
98 
99  connect( mCanvas, SIGNAL( hasCrsTransformEnabledChanged( bool ) ), this, SLOT( onCrsTransformC2R() ) );
100  connect( mRenderer, SIGNAL( hasCrsTransformEnabled( bool ) ), this, SLOT( onCrsTransformR2C() ) );
101 
102  connect( mCanvas, SIGNAL( destinationCrsChanged() ), this, SLOT( onDestCrsC2R() ) );
103  connect( mRenderer, SIGNAL( destinationSrsChanged() ), this, SLOT( onDestCrsR2C() ) );
104 
105  connect( mCanvas, SIGNAL( layersChanged() ), this, SLOT( onLayersC2R() ) );
106  // TODO: layers R2C ? (should not happen!)
107 
108 }
109 
111 {
113 }
114 
116 {
118 }
119 
121 {
123 }
124 
126 {
128 }
129 
131 {
133 }
134 
136 {
138 }
139 
141 {
143 }
144 
146 {
148 }
149 
151 {
153 }
154 
155 
156 
157 QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
158  : QGraphicsView( parent )
159  , mCanvasProperties( new CanvasProperties )
160  , mJob( 0 )
161  , mJobCancelled( false )
162  , mLabelingResults( 0 )
163  , mUseParallelRendering( false )
164  , mDrawRenderingStats( false )
165  , mCache( 0 )
166 {
167  setObjectName( name );
168  mScene = new QGraphicsScene();
169  setScene( mScene );
170  setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
171  setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
172  mLastExtentIndex = -1;
173  mCurrentLayer = NULL;
174  mMapOverview = NULL;
175  mMapTool = NULL;
176  mLastNonZoomMapTool = NULL;
177 
178  mFrozen = false;
179  mRefreshScheduled = false;
180 
182 
183  // by default, the canvas is rendered
184  mRenderFlag = true;
185 
186  setMouseTracking( true );
187  setFocusPolicy( Qt::StrongFocus );
188 
190  connect( mMapRenderer, SIGNAL( datumTransformInfoRequested( const QgsMapLayer*, const QString&, const QString& ) ),
191  this, SLOT( getDatumTransformInfo( const QgsMapLayer*, const QString& , const QString& ) ) );
192 
193  mResizeTimer = new QTimer( this );
194  mResizeTimer->setSingleShot( true );
195  connect( mResizeTimer, SIGNAL( timeout() ), this, SLOT( refresh() ) );
196 
197  // create map canvas item which will show the map
198  mMap = new QgsMapCanvasMap( this );
199  mScene->addItem( mMap );
200 
201  // project handling
202  connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ),
203  this, SLOT( readProject( const QDomDocument & ) ) );
204  connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ),
205  this, SLOT( writeProject( QDomDocument & ) ) );
206 
208 
209  // class that will sync most of the changes between canvas and (legacy) map renderer
210  // it is parented to map canvas, will be deleted automatically
212 
215  setSceneRect( 0, 0, size().width(), size().height() );
216  mScene->setSceneRect( QRectF( 0, 0, size().width(), size().height() ) );
217 
218  moveCanvasContents( true );
219 
220  connect( &mMapUpdateTimer, SIGNAL( timeout() ), SLOT( mapUpdateTimeout() ) );
221  mMapUpdateTimer.setInterval( 250 );
222 
223 #ifdef Q_OS_WIN
224  // Enable touch event on Windows.
225  // Qt on Windows needs to be told it can take touch events or else it ignores them.
226  grabGesture( Qt::PinchGesture );
227  viewport()->setAttribute( Qt::WA_AcceptTouchEvents );
228 #endif
229 
230  refresh();
231 
232 } // QgsMapCanvas ctor
233 
234 
236 {
237  if ( mMapTool )
238  {
239  mMapTool->deactivate();
240  mMapTool = NULL;
241  }
242  mLastNonZoomMapTool = NULL;
243 
244  // delete canvas items prior to deleteing the canvas
245  // because they might try to update canvas when it's
246  // already being destructed, ends with segfault
247  QList<QGraphicsItem*> list = mScene->items();
248  QList<QGraphicsItem*>::iterator it = list.begin();
249  while ( it != list.end() )
250  {
251  QGraphicsItem* item = *it;
252  delete item;
253  ++it;
254  }
255 
256  mScene->deleteLater(); // crashes in python tests on windows
257 
258  delete mMapRenderer;
259  // mCanvasProperties auto-deleted via std::auto_ptr
260  // CanvasProperties struct has its own dtor for freeing resources
261 
262  if ( mJob )
263  {
264  mJob->cancel();
265  Q_ASSERT( mJob == 0 );
266  }
267 
268  delete mCache;
269 
270  delete mLabelingResults;
271 
272 } // dtor
273 
275 {
277 
278  if ( mMapOverview )
279  mMapOverview->enableAntiAliasing( theFlag );
280 } // anti aliasing
281 
282 void QgsMapCanvas::useImageToRender( bool theFlag )
283 {
284  Q_UNUSED( theFlag );
285 }
286 
288 {
289  return mMap;
290 }
291 
293 {
294  return mMapRenderer;
295 }
296 
297 
299 {
300  const QStringList& layers = mapSettings().layers();
301  if ( index >= 0 && index < ( int ) layers.size() )
302  return QgsMapLayerRegistry::instance()->mapLayer( layers[index] );
303  else
304  return NULL;
305 }
306 
307 
309 {
311 }
312 
314 {
315  return mapSettings().scale();
316 } // scale
317 
318 void QgsMapCanvas::setDirty( bool dirty )
319 {
320  if ( dirty )
321  refresh();
322 }
323 
325 {
326  return false;
327 }
328 
329 
330 
332 {
333  return mJob != 0;
334 } // isDrawing
335 
336 
337 // return the current coordinate transform based on the extents and
338 // device size
340 {
341  return &mapSettings().mapToPixel();
342 }
343 
344 void QgsMapCanvas::setLayerSet( QList<QgsMapCanvasLayer> &layers )
345 {
346  // create layer set
347  QStringList layerSet, layerSetOverview;
348 
349  int i;
350  for ( i = 0; i < layers.size(); i++ )
351  {
352  QgsMapCanvasLayer &lyr = layers[i];
353  if ( !lyr.layer() )
354  {
355  continue;
356  }
357 
358  if ( lyr.isVisible() )
359  {
360  layerSet.push_back( lyr.layer()->id() );
361  }
362 
363  if ( lyr.isInOverview() )
364  {
365  layerSetOverview.push_back( lyr.layer()->id() );
366  }
367  }
368 
369  const QStringList& layerSetOld = mapSettings().layers();
370 
371  bool layerSetChanged = layerSetOld != layerSet;
372 
373  // update only if needed
374  if ( layerSetChanged )
375  {
376  QgsDebugMsg( "Layers changed to: " + layerSet.join( ", " ) );
377 
378  for ( i = 0; i < layerCount(); i++ )
379  {
380  // Add check if vector layer when disconnecting from selectionChanged slot
381  // Ticket #811 - racicot
383  disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
384  QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
385  if ( isVectLyr )
386  {
387  disconnect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
388  }
389  }
390 
391  mSettings.setLayers( layerSet );
392 
393  for ( i = 0; i < layerCount(); i++ )
394  {
395  // Add check if vector layer when connecting to selectionChanged slot
396  // Ticket #811 - racicot
398  connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
399  QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
400  if ( isVectLyr )
401  {
402  connect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
403  }
404  }
405 
406  QgsDebugMsg( "Layers have changed, refreshing" );
407  emit layersChanged();
408 
409  refresh();
410  }
411 
412  if ( mMapOverview )
413  {
414  const QStringList& layerSetOvOld = mMapOverview->layerSet();
415  if ( layerSetOvOld != layerSetOverview )
416  {
417  mMapOverview->setLayerSet( layerSetOverview );
418  }
419 
420  // refresh overview maplayers even if layer set is the same
421  // because full extent might have changed
422  updateOverview();
423  }
424 } // setLayerSet
425 
427 {
428  if ( mMapOverview )
429  {
430  // disconnect old map overview if exists
431  disconnect( this, SIGNAL( hasCrsTransformEnabledChanged( bool ) ),
432  mMapOverview, SLOT( hasCrsTransformEnabled( bool ) ) );
433  disconnect( this, SIGNAL( destinationCrsChanged() ),
434  mMapOverview, SLOT( destinationSrsChanged() ) );
435 
436  // map overview is not owned by map canvas so don't delete it...
437  }
438 
439  mMapOverview = overview;
440 
441  if ( overview )
442  {
443  // connect to the map render to copy its projection settings
444  connect( this, SIGNAL( hasCrsTransformEnabledChanged( bool ) ),
445  overview, SLOT( hasCrsTransformEnabled( bool ) ) );
446  connect( this, SIGNAL( destinationCrsChanged() ),
447  overview, SLOT( destinationSrsChanged() ) );
448  }
449 }
450 
452 {
453  return mSettings;
454 }
455 
457 {
458  if ( mSettings.hasCrsTransformEnabled() == enabled )
459  return;
460 
462 
463  refresh();
464 
465  emit hasCrsTransformEnabledChanged( enabled );
466 }
467 
469 {
470  if ( mSettings.destinationCrs() == crs )
471  return;
472 
474  {
475  // try to reproject current extent to the new one
476  QgsRectangle rect;
477  if ( !mSettings.visibleExtent().isEmpty() )
478  {
479  QgsCoordinateTransform transform( mSettings.destinationCrs(), crs );
480  rect = transform.transformBoundingBox( mSettings.visibleExtent() );
481  }
482  if ( !rect.isEmpty() )
483  {
484  setExtent( rect );
485  }
486 
487  QgsDebugMsg( "refreshing after destination CRS changed" );
488  refresh();
489  }
490 
492 
493  emit destinationCrsChanged();
494 }
495 
497 {
498  return mLabelingResults;
499 }
500 
502 {
503  if ( enabled == isCachingEnabled() )
504  return;
505 
506  if ( enabled )
507  {
509  }
510  else
511  {
512  delete mCache;
513  mCache = 0;
514  }
515 }
516 
518 {
519  return mCache != 0;
520 }
521 
523 {
524  if ( mCache )
525  mCache->clear();
526 }
527 
529 {
530  mUseParallelRendering = enabled;
531 }
532 
534 {
535  return mUseParallelRendering;
536 }
537 
538 void QgsMapCanvas::setMapUpdateInterval( int timeMiliseconds )
539 {
540  mMapUpdateTimer.setInterval( timeMiliseconds );
541 }
542 
544 {
545  return mMapUpdateTimer.interval();
546 }
547 
548 
550 {
551  // redraw overview
552  if ( mMapOverview )
553  {
555  }
556 }
557 
558 
560 {
561  return mCurrentLayer;
562 }
563 
564 
566 {
567  if ( !mSettings.hasValidSettings() )
568  {
569  QgsDebugMsg( "CANVAS refresh - invalid settings -> nothing to do" );
570  return;
571  }
572 
573  if ( !mRenderFlag || mFrozen ) // do we really need two flags controlling rendering?
574  {
575  QgsDebugMsg( "CANVAS render flag off" );
576  return;
577  }
578 
579  if ( mRefreshScheduled )
580  {
581  QgsDebugMsg( "CANVAS refresh already scheduled" );
582  return;
583  }
584 
585  mRefreshScheduled = true;
586 
587  QgsDebugMsg( "CANVAS refresh scheduling" );
588 
589  // schedule a refresh
590  QTimer::singleShot( 1, this, SLOT( refreshMap() ) );
591 } // refresh
592 
594 {
595  Q_ASSERT( mRefreshScheduled );
596 
597  QgsDebugMsg( "CANVAS refresh!" );
598 
599  stopRendering(); // if any...
600 
601  // from now on we can accept refresh requests again
602  mRefreshScheduled = false;
603 
604  //update $map variable to canvas
605  QgsExpression::setSpecialColumn( "$map", tr( "canvas" ) );
606 
607  // create the renderer job
608  Q_ASSERT( mJob == 0 );
609  mJobCancelled = false;
610  if ( mUseParallelRendering )
612  else
614  connect( mJob, SIGNAL( finished() ), SLOT( rendererJobFinished() ) );
615  mJob->setCache( mCache );
616 
617  QStringList layersForGeometryCache;
618  foreach ( QString id, mSettings.layers() )
619  {
620  if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( id ) ) )
621  {
622  if ( vl->isEditable() )
623  layersForGeometryCache << id;
624  }
625  }
626  mJob->setRequestedGeometryCacheForLayers( layersForGeometryCache );
627 
628  mJob->start();
629 
630  mMapUpdateTimer.start();
631 }
632 
633 
635 {
636  QgsDebugMsg( QString( "CANVAS finish! %1" ).arg( !mJobCancelled ) );
637 
638  mMapUpdateTimer.stop();
639 
640  // TODO: would be better to show the errors in message bar
641  foreach ( const QgsMapRendererJob::Error& error, mJob->errors() )
642  {
643  QgsMessageLog::logMessage( error.layerID + " :: " + error.message, tr( "Rendering" ) );
644  }
645 
646  if ( !mJobCancelled )
647  {
648  // take labeling results before emitting renderComplete, so labeling map tools
649  // connected to signal work with correct results
650  delete mLabelingResults;
652 
653  QImage img = mJob->renderedImage();
654 
655  // emit renderComplete to get our decorations drawn
656  QPainter p( &img );
657  emit renderComplete( &p );
658 
659  QSettings settings;
660  if ( settings.value( "/Map/logCanvasRefreshEvent", false ).toBool() )
661  {
662  QString logMsg = tr( "Canvas refresh: %1 ms" ).arg( mJob->renderingTime() );
663  QgsMessageLog::logMessage( logMsg, tr( "Rendering" ) );
664  }
665 
666  if ( mDrawRenderingStats )
667  {
668  int w = img.width(), h = img.height();
669  QFont fnt = p.font();
670  fnt.setBold( true );
671  p.setFont( fnt );
672  int lh = p.fontMetrics().height() * 2;
673  QRect r( 0, h - lh, w, lh );
674  p.setPen( Qt::NoPen );
675  p.setBrush( QColor( 0, 0, 0, 110 ) );
676  p.drawRect( r );
677  p.setPen( Qt::white );
678  QString msg = QString( "%1 :: %2 ms" ).arg( mUseParallelRendering ? "PARALLEL" : "SEQUENTIAL" ).arg( mJob->renderingTime() );
679  p.drawText( r, msg, QTextOption( Qt::AlignCenter ) );
680  }
681 
682  p.end();
683 
685  }
686 
687  // now we are in a slot called from mJob - do not delete it immediately
688  // so the class is still valid when the execution returns to the class
689  mJob->deleteLater();
690  mJob = 0;
691 }
692 
694 {
696 }
697 
698 
700 {
701  if ( mJob )
702  {
703  QgsDebugMsg( "CANVAS stop rendering!" );
704  mJobCancelled = true;
705  mJob->cancel();
706  Q_ASSERT( mJob == 0 ); // no need to delete here: already deleted in finished()
707  }
708 }
709 
711 {
712 }
713 
714 //the format defaults to "PNG" if not specified
715 void QgsMapCanvas::saveAsImage( QString theFileName, QPixmap * theQPixmap, QString theFormat )
716 {
717  //
718  //check if the optional QPaintDevice was supplied
719  //
720  if ( theQPixmap != NULL )
721  {
722  // render
723  QPainter painter;
724  painter.begin( theQPixmap );
725  QgsMapRendererCustomPainterJob job( mSettings, &painter );
726  job.start();
727  job.waitForFinished();
728  emit renderComplete( &painter );
729  painter.end();
730 
731  theQPixmap->save( theFileName, theFormat.toLocal8Bit().data() );
732  }
733  else //use the map view
734  {
735  mMap->contentImage().save( theFileName, theFormat.toLocal8Bit().data() );
736  }
737  //create a world file to go with the image...
739  QString myHeader;
740  // note: use 17 places of precision for all numbers output
741  //Pixel XDim
742  myHeader += qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
743  //Rotation on y axis - hard coded
744  myHeader += "0 \r\n";
745  //Rotation on x axis - hard coded
746  myHeader += "0 \r\n";
747  //Pixel YDim - almost always negative - see
748  //http://en.wikipedia.org/wiki/World_file#cite_note-2
749  myHeader += "-" + qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
750  //Origin X (center of top left cell)
751  myHeader += qgsDoubleToString( myRect.xMinimum() + ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
752  //Origin Y (center of top left cell)
753  myHeader += qgsDoubleToString( myRect.yMaximum() - ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
754  QFileInfo myInfo = QFileInfo( theFileName );
755  // allow dotted names
756  QString myWorldFileName = myInfo.absolutePath() + "/" + myInfo.completeBaseName() + "." + theFormat + "w";
757  QFile myWorldFile( myWorldFileName );
758  if ( !myWorldFile.open( QIODevice::WriteOnly ) ) //don't use QIODevice::Text
759  {
760  return;
761  }
762  QTextStream myStream( &myWorldFile );
763  myStream << myHeader;
764 } // saveAsImage
765 
766 
767 
769 {
770  return mapSettings().visibleExtent();
771 } // extent
772 
774 {
775  return mapSettings().fullExtent();
776 } // extent
777 
778 
780 {
781  QgsRectangle current = extent();
782 
783  if ( r == current )
784  return;
785 
786  if ( r.isEmpty() )
787  {
788  QgsDebugMsg( "Empty extent - keeping old extent with new center!" );
789  QgsRectangle e( QgsPoint( r.center().x() - current.width() / 2.0, r.center().y() - current.height() / 2.0 ),
790  QgsPoint( r.center().x() + current.width() / 2.0, r.center().y() + current.height() / 2.0 ) );
791  mSettings.setExtent( e );
792  }
793  else
794  {
795  mSettings.setExtent( r );
796  }
797  emit extentsChanged();
798  updateScale();
799  if ( mLastExtent.size() > 20 )
800  mLastExtent.removeAt( 0 );
801 
802  //clear all extent items after current index
803  for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
804  {
805  mLastExtent.removeAt( i );
806  }
807 
808  mLastExtent.append( extent() ) ;
809 
810  // adjust history to no more than 20
811  if ( mLastExtent.size() > 20 )
812  {
813  mLastExtent.removeAt( 0 );
814  }
815 
816  // the last item is the current extent
817  mLastExtentIndex = mLastExtent.size() - 1;
818 
819  // update controls' enabled state
820  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
821  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
822  // notify canvas items of change
824 
825 } // setExtent
826 
827 
829 {
830  emit scaleChanged( mapSettings().scale() );
831 }
832 
833 
835 {
836  refresh();
837 } // clear
838 
839 
840 
842 {
844  // If the full extent is an empty set, don't do the zoom
845  if ( !extent.isEmpty() )
846  {
847  // Add a 5% margin around the full extent
848  extent.scale( 1.05 );
849  setExtent( extent );
850  }
851  refresh();
852 
853 } // zoomToFullExtent
854 
855 
856 
858 {
859  if ( mLastExtentIndex > 0 )
860  {
863  emit extentsChanged();
864  updateScale();
865  refresh();
866  // update controls' enabled state
867  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
868  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
869  // notify canvas items of change
871  }
872 
873 } // zoomToPreviousExtent
874 
876 {
877  if ( mLastExtentIndex < mLastExtent.size() - 1 )
878  {
881  emit extentsChanged();
882  updateScale();
883  refresh();
884  // update controls' enabled state
885  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
886  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
887  // notify canvas items of change
889  }
890 }// zoomToNextExtent
891 
893 {
894  mLastExtent.clear(); // clear the zoom history list
895  mLastExtent.append( extent() ) ; // set the current extent in the list
896  mLastExtentIndex = mLastExtent.size() - 1;
897  // update controls' enabled state
900 }// clearExtentHistory
901 
902 
904 {
906 }
907 
909 {
910  if ( layer == NULL )
911  {
912  // use current layer by default
913  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
914  }
915 
916  if ( layer == NULL )
917  {
918  return;
919  }
920 
921  if ( layer->selectedFeatureCount() == 0 )
922  {
923  return;
924  }
925 
927 
928  // no selected features, only one selected point feature
929  //or two point features with the same x- or y-coordinates
930  if ( rect.isEmpty() )
931  {
932  // zoom in
933  QgsPoint c = rect.center();
934  rect = extent();
935  rect.scale( 1.0, &c );
936  }
937  //zoom to an area
938  else
939  {
940  // Expand rect to give a bit of space around the selected
941  // objects so as to keep them clear of the map boundaries
942  // The same 5% should apply to all margins.
943  rect.scale( 1.05 );
944  }
945 
946  setExtent( rect );
947  refresh();
948 } // zoomToSelected
949 
951 {
952  if ( layer == NULL )
953  {
954  // use current layer by default
955  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
956  }
957 
958  if ( layer == NULL )
959  {
960  return;
961  }
962 
963  if ( layer->selectedFeatureCount() == 0 )
964  {
965  return;
966  }
967 
969  setExtent( QgsRectangle( rect.center(), rect.center() ) );
970  refresh();
971 } // panToSelected
972 
973 void QgsMapCanvas::keyPressEvent( QKeyEvent * e )
974 {
975  if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
976  {
977  emit keyPressed( e );
978  return;
979  }
980 
981  QPainter paint;
982  QPen pen( Qt::gray );
983  QgsPoint ll, ur;
984 
985  if ( ! mCanvasProperties->mouseButtonDown )
986  {
987  // Don't want to interfer with mouse events
988 
989  QgsRectangle currentExtent = mapSettings().visibleExtent();
990  double dx = qAbs(( currentExtent.xMaximum() - currentExtent.xMinimum() ) / 4 );
991  double dy = qAbs(( currentExtent.yMaximum() - currentExtent.yMinimum() ) / 4 );
992 
993  switch ( e->key() )
994  {
995  case Qt::Key_Left:
996  QgsDebugMsg( "Pan left" );
997 
998  currentExtent.setXMinimum( currentExtent.xMinimum() - dx );
999  currentExtent.setXMaximum( currentExtent.xMaximum() - dx );
1000  setExtent( currentExtent );
1001  refresh();
1002  break;
1003 
1004  case Qt::Key_Right:
1005  QgsDebugMsg( "Pan right" );
1006 
1007  currentExtent.setXMinimum( currentExtent.xMinimum() + dx );
1008  currentExtent.setXMaximum( currentExtent.xMaximum() + dx );
1009  setExtent( currentExtent );
1010  refresh();
1011  break;
1012 
1013  case Qt::Key_Up:
1014  QgsDebugMsg( "Pan up" );
1015 
1016  currentExtent.setYMaximum( currentExtent.yMaximum() + dy );
1017  currentExtent.setYMinimum( currentExtent.yMinimum() + dy );
1018  setExtent( currentExtent );
1019  refresh();
1020  break;
1021 
1022  case Qt::Key_Down:
1023  QgsDebugMsg( "Pan down" );
1024 
1025  currentExtent.setYMaximum( currentExtent.yMaximum() - dy );
1026  currentExtent.setYMinimum( currentExtent.yMinimum() - dy );
1027  setExtent( currentExtent );
1028  refresh();
1029  break;
1030 
1031 
1032 
1033  case Qt::Key_Space:
1034  QgsDebugMsg( "Pressing pan selector" );
1035 
1036  //mCanvasProperties->dragging = true;
1037  if ( ! e->isAutoRepeat() )
1038  {
1039  mCanvasProperties->panSelectorDown = true;
1040  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1041  }
1042  break;
1043 
1044  case Qt::Key_PageUp:
1045  QgsDebugMsg( "Zoom in" );
1046  zoomIn();
1047  break;
1048 
1049  case Qt::Key_PageDown:
1050  QgsDebugMsg( "Zoom out" );
1051  zoomOut();
1052  break;
1053 
1054  case Qt::Key_P:
1056  refresh();
1057  break;
1058 
1059  case Qt::Key_S:
1061  refresh();
1062  break;
1063 
1064  default:
1065  // Pass it on
1066  if ( mMapTool )
1067  {
1068  mMapTool->keyPressEvent( e );
1069  }
1070  else e->ignore();
1071 
1072  QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
1073  }
1074  }
1075 
1076  emit keyPressed( e );
1077 
1078 } //keyPressEvent()
1079 
1080 void QgsMapCanvas::keyReleaseEvent( QKeyEvent * e )
1081 {
1082  QgsDebugMsg( "keyRelease event" );
1083 
1084  switch ( e->key() )
1085  {
1086  case Qt::Key_Space:
1087  if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
1088  {
1089  QgsDebugMsg( "Releasing pan selector" );
1090 
1091  mCanvasProperties->panSelectorDown = false;
1092  panActionEnd( mCanvasProperties->mouseLastXY );
1093  }
1094  break;
1095 
1096  default:
1097  // Pass it on
1098  if ( mMapTool )
1099  {
1100  mMapTool->keyReleaseEvent( e );
1101  }
1102  else e->ignore();
1103 
1104  QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
1105  }
1106 
1107  emit keyReleased( e );
1108 
1109 } //keyReleaseEvent()
1110 
1111 
1113 {
1114  // call handler of current map tool
1115  if ( mMapTool )
1117 } // mouseDoubleClickEvent
1118 
1119 
1120 void QgsMapCanvas::mousePressEvent( QMouseEvent * e )
1121 {
1122  //use middle mouse button for panning, map tools won't receive any events in that case
1123  if ( e->button() == Qt::MidButton )
1124  {
1125  mCanvasProperties->panSelectorDown = true;
1126  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
1127  }
1128  else
1129  {
1130 
1131  // call handler of current map tool
1132  if ( mMapTool )
1133  mMapTool->canvasPressEvent( e );
1134  }
1135 
1136  if ( mCanvasProperties->panSelectorDown )
1137  {
1138  return;
1139  }
1140 
1141  mCanvasProperties->mouseButtonDown = true;
1142  mCanvasProperties->rubberStartPoint = e->pos();
1143 
1144 } // mousePressEvent
1145 
1146 
1147 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent * e )
1148 {
1149  //use middle mouse button for panning, map tools won't receive any events in that case
1150  if ( e->button() == Qt::MidButton )
1151  {
1152  mCanvasProperties->panSelectorDown = false;
1153  panActionEnd( mCanvasProperties->mouseLastXY );
1154  }
1155  else
1156  {
1157  // call handler of current map tool
1158  if ( mMapTool )
1159  {
1160  // right button was pressed in zoom tool? return to previous non zoom tool
1161  if ( e->button() == Qt::RightButton && mMapTool->isTransient() )
1162  {
1163  QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
1164  QString( mLastNonZoomMapTool ? "not null." : "null." ) );
1165 
1166  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1167 
1168  // change to older non-zoom tool
1169  if ( mLastNonZoomMapTool
1170  && ( !mLastNonZoomMapTool->isEditTool() || ( vlayer && vlayer->isEditable() ) ) )
1171  {
1173  mLastNonZoomMapTool = NULL;
1174  setMapTool( t );
1175  }
1176  return;
1177  }
1179  }
1180  }
1181 
1182 
1183  mCanvasProperties->mouseButtonDown = false;
1184 
1185  if ( mCanvasProperties->panSelectorDown )
1186  return;
1187 
1188 } // mouseReleaseEvent
1189 
1190 void QgsMapCanvas::resizeEvent( QResizeEvent * e )
1191 {
1192  QGraphicsView::resizeEvent( e );
1193  mResizeTimer->start( 500 );
1194 
1195  QSize lastSize = size();
1196 
1197  mSettings.setOutputSize( lastSize );
1199 
1200  mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1201 
1202  moveCanvasContents( true );
1203 
1204  // notify canvas items of change
1206 
1207  updateScale();
1208 
1209  //refresh();
1210 
1211  emit extentsChanged();
1212 }
1213 
1214 void QgsMapCanvas::paintEvent( QPaintEvent *e )
1215 {
1216  // no custom event handling anymore
1217 
1218  QGraphicsView::paintEvent( e );
1219 } // paintEvent
1220 
1222 {
1223  QList<QGraphicsItem*> list = mScene->items();
1224  QList<QGraphicsItem*>::iterator it = list.begin();
1225  while ( it != list.end() )
1226  {
1227  QgsMapCanvasItem* item = dynamic_cast<QgsMapCanvasItem *>( *it );
1228 
1229  if ( item )
1230  {
1231  item->updatePosition();
1232  }
1233 
1234  ++it;
1235  }
1236 }
1237 
1238 
1239 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
1240 {
1241  // Zoom the map canvas in response to a mouse wheel event. Moving the
1242  // wheel forward (away) from the user zooms in
1243 
1244  QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
1245 
1246  if ( mMapTool )
1247  {
1248  mMapTool->wheelEvent( e );
1249  }
1250 
1251  if ( QgsApplication::keyboardModifiers() )
1252  {
1253  // leave the wheel for map tools if any modifier pressed
1254  return;
1255  }
1256 
1257  switch ( mWheelAction )
1258  {
1259  case WheelZoom:
1260  // zoom without changing extent
1261  if ( e->delta() > 0 )
1262  zoomIn();
1263  else
1264  zoomOut();
1265  break;
1266 
1267  case WheelZoomAndRecenter:
1268  // zoom and don't change extent
1269  zoomWithCenter( e->x(), e->y(), e->delta() > 0 );
1270  break;
1271 
1273  {
1274  // zoom map to mouse cursor
1275  double scaleFactor = e->delta() > 0 ? 1 / mWheelZoomFactor : mWheelZoomFactor;
1276 
1277  QgsPoint oldCenter( mapSettings().visibleExtent().center() );
1278  QgsPoint mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
1279  QgsPoint newCenter( mousePos.x() + (( oldCenter.x() - mousePos.x() ) * scaleFactor ),
1280  mousePos.y() + (( oldCenter.y() - mousePos.y() ) * scaleFactor ) );
1281 
1282  // same as zoomWithCenter (no coordinate transformations are needed)
1284  extent.scale( scaleFactor, &newCenter );
1285  setExtent( extent );
1286  refresh();
1287  break;
1288  }
1289 
1290  case WheelNothing:
1291  // well, nothing!
1292  break;
1293  }
1294 }
1295 
1296 void QgsMapCanvas::setWheelAction( WheelAction action, double factor )
1297 {
1298  mWheelAction = action;
1299  mWheelZoomFactor = factor;
1300 }
1301 
1303 {
1305 }
1306 
1308 {
1310 }
1311 
1312 void QgsMapCanvas::zoomScale( double newScale )
1313 {
1314  zoomByFactor( newScale / scale() );
1315 }
1316 
1317 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
1318 {
1319  double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1320 
1321  // transform the mouse pos to map coordinates
1322  QgsPoint center = getCoordinateTransform()->toMapPoint( x, y );
1324  r.scale( scaleFactor, &center );
1325  setExtent( r );
1326  refresh();
1327 }
1328 
1329 void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
1330 {
1331  mCanvasProperties->mouseLastXY = e->pos();
1332 
1333  if ( mCanvasProperties->panSelectorDown )
1334  {
1335  panAction( e );
1336  }
1337  else
1338  {
1339  // call handler of current map tool
1340  if ( mMapTool )
1341  mMapTool->canvasMoveEvent( e );
1342  }
1343 
1344  // show x y on status bar
1345  QPoint xy = e->pos();
1347  emit xyCoordinates( coord );
1348 } // mouseMoveEvent
1349 
1350 
1351 
1354 {
1355  if ( !tool )
1356  return;
1357 
1358  if ( mMapTool )
1359  {
1360  disconnect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1361  mMapTool->deactivate();
1362  }
1363 
1364  if ( tool->isTransient() && mMapTool && !mMapTool->isTransient() )
1365  {
1366  // if zoom or pan tool will be active, save old tool
1367  // to bring it back on right click
1368  // (but only if it wasn't also zoom or pan tool)
1370  }
1371  else
1372  {
1373  mLastNonZoomMapTool = NULL;
1374  }
1375 
1376  QgsMapTool* oldTool = mMapTool;
1377 
1378  // set new map tool and activate it
1379  mMapTool = tool;
1380  if ( mMapTool )
1381  {
1382  connect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1383  mMapTool->activate();
1384  }
1385 
1386  emit mapToolSet( mMapTool );
1387  emit mapToolSet( mMapTool, oldTool );
1388 } // setMapTool
1389 
1391 {
1392  if ( mMapTool && mMapTool == tool )
1393  {
1394  mMapTool->deactivate();
1395  mMapTool = NULL;
1396  emit mapToolSet( NULL );
1397  emit mapToolSet( NULL, mMapTool );
1398  setCursor( Qt::ArrowCursor );
1399  }
1400 
1401  if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1402  {
1403  mLastNonZoomMapTool = NULL;
1404  }
1405 }
1406 
1408 void QgsMapCanvas::setCanvasColor( const QColor & theColor )
1409 {
1410  // background of map's pixmap
1411  mSettings.setBackgroundColor( theColor );
1412 
1413  // background of the QGraphicsView
1414  QBrush bgBrush( theColor );
1415  setBackgroundBrush( bgBrush );
1416 #if 0
1417  QPalette palette;
1418  palette.setColor( backgroundRole(), theColor );
1419  setPalette( palette );
1420 #endif
1421 
1422  // background of QGraphicsScene
1423  mScene->setBackgroundBrush( bgBrush );
1424 } // setBackgroundColor
1425 
1427 {
1428  return mScene->backgroundBrush().color();
1429 }
1430 
1431 void QgsMapCanvas::setSelectionColor( const QColor& color )
1432 {
1433  mSettings.setSelectionColor( color );
1434 }
1435 
1437 {
1438  return mapSettings().layers().size();
1439 } // layerCount
1440 
1441 
1442 QList<QgsMapLayer*> QgsMapCanvas::layers() const
1443 {
1444  QList<QgsMapLayer*> lst;
1445  foreach ( QString layerID, mapSettings().layers() )
1446  {
1448  if ( layer )
1449  lst.append( layer );
1450  }
1451  return lst;
1452 }
1453 
1454 
1456 {
1457  // called when a layer has changed visibility setting
1458 
1459  refresh();
1460 
1461 } // layerStateChange
1462 
1463 
1464 
1465 void QgsMapCanvas::freeze( bool frz )
1466 {
1467  mFrozen = frz;
1468 } // freeze
1469 
1471 {
1472  return mFrozen;
1473 } // freeze
1474 
1475 
1477 {
1479  return mMap->paintDevice();
1481 }
1482 
1484 {
1485  return mapSettings().mapUnitsPerPixel();
1486 } // mapUnitsPerPixel
1487 
1488 
1490 {
1491  if ( mSettings.mapUnits() == u )
1492  return;
1493 
1494  QgsDebugMsg( "Setting map units to " + QString::number( static_cast<int>( u ) ) );
1495  mSettings.setMapUnits( u );
1496 
1497  updateScale();
1498 
1499  refresh(); // this will force the scale bar to be updated
1500 
1501  emit mapUnitsChanged();
1502 }
1503 
1504 
1506 {
1507  return mapSettings().mapUnits();
1508 }
1509 
1510 
1511 void QgsMapCanvas::setRenderFlag( bool theFlag )
1512 {
1513  mRenderFlag = theFlag;
1514 
1515  if ( mRenderFlag )
1516  {
1517  refresh();
1518  }
1519  else
1520  stopRendering();
1521 }
1522 
1523 void QgsMapCanvas::connectNotify( const char * signal )
1524 {
1525  Q_UNUSED( signal );
1526  QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
1527 } //connectNotify
1528 
1529 
1530 
1532 {
1533  return mMapTool;
1534 }
1535 
1536 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
1537 {
1538  // move map image and other items to standard position
1539  moveCanvasContents( true ); // true means reset
1540 
1541  // use start and end box points to calculate the extent
1542  QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
1543  QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );
1544 
1545  double dx = qAbs( end.x() - start.x() );
1546  double dy = qAbs( end.y() - start.y() );
1547 
1548  // modify the extent
1550 
1551  if ( end.x() < start.x() )
1552  {
1553  r.setXMinimum( r.xMinimum() + dx );
1554  r.setXMaximum( r.xMaximum() + dx );
1555  }
1556  else
1557  {
1558  r.setXMinimum( r.xMinimum() - dx );
1559  r.setXMaximum( r.xMaximum() - dx );
1560  }
1561 
1562  if ( end.y() < start.y() )
1563  {
1564  r.setYMaximum( r.yMaximum() + dy );
1565  r.setYMinimum( r.yMinimum() + dy );
1566 
1567  }
1568  else
1569  {
1570  r.setYMaximum( r.yMaximum() - dy );
1571  r.setYMinimum( r.yMinimum() - dy );
1572 
1573  }
1574 
1575  setExtent( r );
1576 
1577  r = mapSettings().visibleExtent();
1578 
1579  refresh();
1580 }
1581 
1582 void QgsMapCanvas::panAction( QMouseEvent * e )
1583 {
1584  Q_UNUSED( e );
1585 
1586  // move all map canvas items
1588 }
1589 
1591 {
1592  QPoint pnt( 0, 0 );
1593  if ( !reset )
1594  pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
1595 
1596  setSceneRect( -pnt.x(), -pnt.y(), size().width(), size().height() );
1597 }
1598 
1600 {
1601  Q_UNUSED( mapLayer );
1602 }
1603 
1605 {
1606  return mCanvasProperties->mouseLastXY;
1607 }
1608 
1609 void QgsMapCanvas::readProject( const QDomDocument & doc )
1610 {
1611  QDomNodeList nodes = doc.elementsByTagName( "mapcanvas" );
1612  if ( nodes.count() )
1613  {
1614  QDomNode node = nodes.item( 0 );
1615 
1616  QgsMapSettings tmpSettings;
1617  tmpSettings.readXML( node );
1618  setMapUnits( tmpSettings.mapUnits() );
1619  setExtent( tmpSettings.extent() );
1621  setDestinationCrs( tmpSettings.destinationCrs() );
1622  // TODO: read only units, extent, projections, dest CRS
1623 
1624  clearExtentHistory(); // clear the extent history on project load
1625  }
1626  else
1627  {
1628  QgsDebugMsg( "Couldn't read mapcanvas information from project" );
1629  }
1630 }
1631 
1632 void QgsMapCanvas::writeProject( QDomDocument & doc )
1633 {
1634  // create node "mapcanvas" and call mMapRenderer->writeXML()
1635 
1636  QDomNodeList nl = doc.elementsByTagName( "qgis" );
1637  if ( !nl.count() )
1638  {
1639  QgsDebugMsg( "Unable to find qgis element in project file" );
1640  return;
1641  }
1642  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element ok
1643 
1644  QDomElement mapcanvasNode = doc.createElement( "mapcanvas" );
1645  qgisNode.appendChild( mapcanvasNode );
1646 
1647  mSettings.writeXML( mapcanvasNode, doc );
1648  // TODO: store only units, extent, projections, dest CRS
1649 }
1650 
1652 void QgsMapCanvas::getDatumTransformInfo( const QgsMapLayer* ml, const QString& srcAuthId, const QString& destAuthId )
1653 {
1654  if ( !ml )
1655  {
1656  return;
1657  }
1658 
1659  //check if default datum transformation available
1660  QSettings s;
1661  QString settingsString = "/Projections/" + srcAuthId + "//" + destAuthId;
1662  QVariant defaultSrcTransform = s.value( settingsString + "_srcTransform" );
1663  QVariant defaultDestTransform = s.value( settingsString + "_destTransform" );
1664  if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
1665  {
1666  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, defaultSrcTransform.toInt(), defaultDestTransform.toInt() );
1667  return;
1668  }
1669 
1670  const QgsCoordinateReferenceSystem& srcCRS = QgsCRSCache::instance()->crsByAuthId( srcAuthId );
1671  const QgsCoordinateReferenceSystem& destCRS = QgsCRSCache::instance()->crsByAuthId( destAuthId );
1672 
1673  if ( !s.value( "/Projections/showDatumTransformDialog", false ).toBool() )
1674  {
1675  // just use the default transform
1676  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, -1, -1 );
1677  return;
1678  }
1679 
1680  //get list of datum transforms
1681  QList< QList< int > > dt = QgsCoordinateTransform::datumTransformations( srcCRS, destCRS );
1682  if ( dt.size() < 2 )
1683  {
1684  return;
1685  }
1686 
1687  //if several possibilities: present dialog
1688  QgsDatumTransformDialog d( ml->name(), dt );
1689  if ( mMapRenderer && ( d.exec() == QDialog::Accepted ) )
1690  {
1691  int srcTransform = -1;
1692  int destTransform = -1;
1693  QList<int> t = d.selectedDatumTransform();
1694  if ( t.size() > 0 )
1695  {
1696  srcTransform = t.at( 0 );
1697  }
1698  if ( t.size() > 1 )
1699  {
1700  destTransform = t.at( 1 );
1701  }
1702  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, srcTransform, destTransform );
1703  if ( d.rememberSelection() )
1704  {
1705  s.setValue( settingsString + "_srcTransform", srcTransform );
1706  s.setValue( settingsString + "_destTransform", destTransform );
1707  }
1708  }
1709  else
1710  {
1711  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, -1, -1 );
1712  }
1713 }
1714 
1715 void QgsMapCanvas::zoomByFactor( double scaleFactor )
1716 {
1718  r.scale( scaleFactor );
1719  setExtent( r );
1720  refresh();
1721 }
1722 
1724 {
1725  // Find out which layer it was that sent the signal.
1726  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
1727  emit selectionChanged( layer );
1728  refresh();
1729 }
1730 
1731 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent * e )
1732 {
1733  // By default graphics view delegates the drag events to graphics items.
1734  // But we do not want that and by ignoring the drag enter we let the
1735  // parent (e.g. QgisApp) to handle drops of map layers etc.
1736  e->ignore();
1737 }
1738 
1740 {
1741  QgsDebugMsg( "maptool destroyed" );
1742  mMapTool = 0;
1743 }
1744 
1745 #ifdef HAVE_TOUCH
1746 bool QgsMapCanvas::event( QEvent * e )
1747 {
1748  bool done = false;
1749  if ( e->type() == QEvent::Gesture )
1750  {
1751  // call handler of current map tool
1752  if ( mMapTool )
1753  {
1754  done = mMapTool->gestureEvent( static_cast<QGestureEvent*>( e ) );
1755  }
1756  }
1757  else
1758  {
1759  // pass other events to base class
1760  done = QGraphicsView::event( e );
1761  }
1762  return done;
1763 }
1764 #endif
void unsetMapTool(QgsMapTool *mapTool)
Unset the current map tool or last non zoom tool.
QgsMapCanvasMap * mMap
owns pixmap with rendered map and controls rendering
Definition: qgsmapcanvas.h:534
void zoomToSelected(QgsVectorLayer *layer=NULL)
Zoom to the extent of the selected features of current (vector) layer.
void setRequestedGeometryCacheForLayers(const QStringList &layerIds)
Set which vector layers should be cached while rendering.
void updateCanvasItemPositions()
called on resize or changed extent to notify canvas items to change their rectangle ...
QgsMapSettings mSettings
encompases all map settings necessary for map rendering
Definition: qgsmapcanvas.h:528
bool mDrawRenderingStats
Whether to add rendering stats to the rendered image.
Definition: qgsmapcanvas.h:586
void setParallelRenderingEnabled(bool enabled)
Set whether the layers are rendered in parallel or sequentially.
static unsigned index
void mapUpdateTimeout()
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:47
job implementation that renders everything sequentially using a custom painter.
const QgsCoordinateReferenceSystem & crsByAuthId(const QString &authid)
Returns the CRS for authid, e.g.
bool isEmpty() const
test if rectangle is empty
void zoomToNextExtent()
Zoom to the next extent (view)
QGraphicsScene * mScene
graphics scene manages canvas items
Definition: qgsmapcanvas.h:552
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)
virtual void setCanvasColor(const QColor &_newVal)
Write property of QColor bgColor.
void enableOverviewMode(QgsMapOverviewCanvas *overview)
QTimer * mResizeTimer
Definition: qgsmapcanvas.h:592
double scale() const
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
int layerCount() const
return number of layers on the map
bool mUseParallelRendering
Whether layers are rendered sequentially or in parallel.
Definition: qgsmapcanvas.h:583
A widget that displays an overview map.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:164
void clearExtentHistory()
void readXML(QDomNode &theNode)
QgsRectangle fullExtent() const
returns current extent of layer set
QgsMapRenderer * mMapRenderer
all map rendering is done in this class
Definition: qgsmapcanvas.h:531
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.
bool mRefreshScheduled
Flag that allows squashing multiple refresh() calls into just one delayed rendering job...
Definition: qgsmapcanvas.h:543
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:189
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void stopRendering()
stop rendering (if there is any right now)
virtual void canvasMoveEvent(QMouseEvent *e)
Mouse move event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:125
void zoomByFactor(double scaleFactor)
Zoom with the factor supplied. Factor > 1 zooms out, interval (0,1) zooms in.
void mouseReleaseEvent(QMouseEvent *e)
Overridden mouse release event.
QgsRectangle extent() const
returns current extent
void setExtent(const QgsRectangle &r)
Set the extent of the map canvas.
QString qgsDoubleToString(const double &a)
Definition: qgis.h:316
void addLayerCoordinateTransform(const QString &layerId, const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform=-1, int destDatumTransform=-1)
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:439
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)
QgsRectangle visibleExtent() const
QList< QgsMapLayer * > layers() const
return list of layers within map canvas. Added in v1.5
void moveCanvasContents(bool reset=false)
called when panning is in action, reset indicates end of panning
WheelAction mWheelAction
Mouse wheel action.
Definition: qgsmapcanvas.h:568
bool isVisible() const
Definition: qgsmapcanvas.h:84
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'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.
QgsMapOverviewCanvas * mMapOverview
map overview widget - it's controlled by QgsMapCanvas
Definition: qgsmapcanvas.h:537
void refresh()
Repaints the canvas map.
void renderComplete(QPainter *)
Emitted when the canvas has rendered.
void setProjectionsEnabled(bool enabled)
sets whether to use projections for this layer set
~QgsMapCanvas()
Destructor.
const QgsMapToPixel & mapToPixel() const
void keyReleaseEvent(QKeyEvent *e)
Overridden key release event.
QgsMapTool * mapTool()
Returns the currently active tool.
void setLayerSet(const QStringList &layers)
change current layer set
virtual void canvasDoubleClickEvent(QMouseEvent *e)
Mouse double click event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:130
const QgsLabelingResults * labelingResults() const
Get access to the labeling results (may be null)
A non GUI class for rendering a map layer set onto a QPainter.
virtual void canvasPressEvent(QMouseEvent *e)
Mouse press event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:135
void setLayers(const QStringList &layers)
void resizeEvent(QResizeEvent *e)
Overridden resize event.
QgsMapTool * mMapTool
pointer to current map tool
Definition: qgsmapcanvas.h:555
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:105
double x() const
Definition: qgspoint.h:110
void zoomLastStatusChanged(bool)
Emitted when zoom last status changed.
void setCache(QgsMapRendererCache *cache)
Assign a cache to be used for reading and storing rendered images of individual layers.
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void setFlag(Flag flag, bool on=true)
void updateScale()
Emits signal scaleChanged to update scale in main window.
void mouseDoubleClickEvent(QMouseEvent *e)
Overridden mouse double click event.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs)
sets destination coordinate reference system
QgsMapLayer * mCurrentLayer
current layer in legend
Definition: qgsmapcanvas.h:549
void hasCrsTransformEnabledChanged(bool flag)
Emitted when on-the-fly projection has been turned on/off.
void setMapTool(QgsMapTool *mapTool)
Sets the map tool currently being used on the canvas.
void enableAntiAliasing(bool flag)
const QString & name() const
Get the display name of the layer.
virtual void activate()
called when set as currently active map tool
Definition: qgsmaptool.cpp:77
void paintEvent(QPaintEvent *e)
Overridden paint event.
void setCrsTransformEnabled(bool enabled)
sets whether to use projections for this layer set
QgsMapRenderer * mRenderer
Definition: qgsmapcanvas.h:628
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
virtual void keyReleaseEvent(QKeyEvent *e)
Key event for overriding.
Definition: qgsmaptool.cpp:155
int outputDpi() const
Q_DECL_DEPRECATED void showError(QgsMapLayer *mapLayer)
A rectangular graphics item representing the map on the canvas.
Q_DECL_DEPRECATED void clear()
Clear the map canvas.
int mLastExtentIndex
Definition: qgsmapcanvas.h:562
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:194
double scale()
Get the last reported scale of the canvas.
double xMaximum() const
Get the x maximum value (right side of rectangle)
Definition: qgsrectangle.h:179
void zoomNextStatusChanged(bool)
Emitted when zoom next status changed.
QgsMapTool * mLastNonZoomMapTool
previous tool if current is for zooming/panning
Definition: qgsmapcanvas.h:558
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
bool hasValidSettings() const
void clearCache()
Make sure to remove any rendered images from cache (does nothing if cache is not enabled) ...
void mousePressEvent(QMouseEvent *e)
Overridden mouse press event.
void setMapUnits(QGis::UnitType u)
virtual void waitForFinished()
Block until the job has finished.
job implementation that renders all layers in parallel
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void panToSelected(QgsVectorLayer *layer=NULL)
Pan to the selected features of current (vector) layer keeping same extent.
void setLayerSet(QList< QgsMapCanvasLayer > &layers)
const QgsCoordinateReferenceSystem & destinationCrs() const
returns CRS of destination coordinate reference system
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:169
QgsMapCanvas * mCanvas
Definition: qgsmapcanvas.h:627
void keyReleased(QKeyEvent *e)
Emit key release event.
Q_DECL_DEPRECATED QPaintDevice & paintDevice()
void mapToolDestroyed()
called when current maptool is destroyed
bool setExtent(const QgsRectangle &extent)
sets extent and checks whether suitable (returns false if not)
void setMapUnits(QGis::UnitType u)
void getDatumTransformInfo(const QgsMapLayer *ml, const QString &srcAuthId, const QString &destAuthId)
ask user about datum transformation
Q_DECL_DEPRECATED QPaintDevice & canvasPaintDevice()
Accessor for the canvas paint device.
double mapUnitsPerPixel() const
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:92
void wheelEvent(QWheelEvent *e)
Overridden mouse wheel event.
void destinationCrsChanged()
Emitted when map CRS has changed.
int mapUpdateInterval() const
Find out how often map preview should be updated while it is being rendered (in miliseconds) ...
void setRenderFlag(bool theFlag)
Whether to suppress rendering or not.
QGis::UnitType mapUnits() const
QGis::UnitType mapUnits() const
Get the current canvas map units.
virtual void start()
Start the rendering job and immediately return.
void setOutputSize(QSize size, int dpi)
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:91
virtual bool isEditTool()
Check whether this MapTool performs an edit operation.
Definition: qgsmaptool.cpp:177
QgsMapCanvasMap * map()
virtual void wheelEvent(QWheelEvent *e)
Mouse wheel event for overriding.
Definition: qgsmaptool.cpp:145
void refresh()
renders overview and updates panning widget
A class to represent a point geometry.
Definition: qgspoint.h:63
void saveAsImage(QString theFileName, QPixmap *QPixmap=0, QString="PNG")
Save the convtents of the map canvas to disk as an image.
void keyPressed(QKeyEvent *e)
Emit key press event.
QgsMapRendererQImageJob * mJob
Job that takes care of map rendering in background.
Definition: qgsmapcanvas.h:574
void zoomOut()
Zoom out with fixed factor.
void zoomToPreviousExtent()
Zoom to the previous extent (view)
void xyCoordinates(const QgsPoint &p)
emits current mouse position
bool isDrawing()
Find out whether rendering is in progress.
QgsLabelingResults * mLabelingResults
Labeling results from the recently rendered map.
Definition: qgsmapcanvas.h:580
virtual void start()=0
Start the rendering job and immediately return.
QPoint mouseLastXY()
returns last position of mouse cursor
QgsMapLayer * currentLayer()
returns current layer (set by legend widget)
void setWheelAction(WheelAction action, double factor=2)
set wheel action and zoom factor (should be greater than 1)
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:150
bool isCachingEnabled() const
Check whether images of rendered layers are curerently being cached.
QgsPoint toMapCoordinates(int x, int y) const
void clear()
invalidate the cache contents
Abstract base class for all map tools.
Definition: qgsmaptool.h:48
void selectionChangedSlot()
Receives signal about selection change, and pass it on with layer info.
job implementation that renders everything sequentially in one thread
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:440
QTimer mMapUpdateTimer
Timer that periodically fires while map rendering is in progress to update the visible map...
Definition: qgsmapcanvas.h:571
double mWheelZoomFactor
Scale factor multiple for default zoom in/out.
Definition: qgsmapcanvas.h:565
bool mFrozen
Flag indicating if the map canvas is frozen.
Definition: qgsmapcanvas.h:540
void setBackgroundColor(const QColor &color)
QImage contentImage() 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)
bool isInOverview() const
Definition: qgsmapcanvas.h:85
QgsMapRendererCache * mCache
Optionally use cache with rendered map layers for the current map settings.
Definition: qgsmapcanvas.h:589
virtual void canvasReleaseEvent(QMouseEvent *e)
Mouse release event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:140
void setSelectionColor(const QColor &color)
void setLayerSet(const QStringList &layerSet)
updates layer set for overview
void setOutputSize(const QSize &size)
void setYMaximum(double y)
Set the maximum y value.
Definition: qgsrectangle.h:174
void writeProject(QDomDocument &)
called to write map canvas settings to project
void panAction(QMouseEvent *event)
Called when mouse is moving and pan is activated.
void setDestinationCrs(const QgsCoordinateReferenceSystem &crs, bool refreshCoordinateTransformInfo=true)
sets destination coordinate reference system
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
Q_DECL_DEPRECATED QgsMapRenderer * mapRenderer()
void zoomToFullExtent()
Zoom to the full extent of all layers.
bool mRenderFlag
determines whether user has requested to suppress rendering
Definition: qgsmapcanvas.h:546
Class for storing a coordinate reference system (CRS)
void setExtent(const QgsRectangle &rect)
QgsMapCanvasRendererSync(QgsMapCanvas *canvas, QgsMapRenderer *renderer)
QgsRectangle extent() const
void zoomScale(double scale)
Zoom to a specific scale.
Class for doing transforms between two map coordinate systems.
UnitType
Map units that qgis supports.
Definition: qgis.h:229
const QgsMapToPixel * getCoordinateTransform()
Get the current coordinate transform.
void scaleChanged(double)
Emitted when the scale of the map changes.
virtual bool isTransient()
Check whether this MapTool performs a zoom or pan operation.
Definition: qgsmaptool.cpp:172
double y() const
Definition: qgspoint.h:118
virtual void cancel()=0
Stop the rendering job - does not return until the job has terminated.
QStringList layers() const
void enableAntiAliasing(bool theFlag)
used to determine if anti-aliasing is enabled or not
QgsMapLayer * mapLayer(QString theLayerId)
Retrieve a pointer to a loaded layer by id.
void setSelectionColor(const QColor &color)
Set color of selected vector features.
void setMapUpdateInterval(int timeMiliseconds)
Set how often map preview should be updated while it is being rendered (in miliseconds) ...
void layerStateChange()
This slot is connected to the visibility change of one or more layers.
void rendererJobFinished()
called when a renderer job has finished successfully or when it was cancelled
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.
QgsMapCanvas(QWidget *parent=0, const char *name=0)
Constructor.
void setMapUnits(QGis::UnitType mapUnits)
Set map units (needed by project properties dialog)
void updateOverview()
bool isParallelRenderingEnabled() const
Check whether the layers are rendered in parallel or sequentially.
void connectNotify(const char *signal)
debugging member invoked when a connect() is made to this object
Q_DECL_DEPRECATED void setDirty(bool _dirty)
Flag the canvas as dirty and needed a refresh.
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
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:605
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
virtual QgsLabelingResults * takeLabelingResults()=0
Get pointer to internal labeling engine (in order to get access to the results)
void zoomIn()
Zoom in with fixed factor.
virtual bool isEditable() const
Returns true if the provider is in editing mode.
QGis::UnitType mapUnits() const
Represents a vector layer which manages a vector based data sets.
double size
Definition: qgssvgcache.cpp:77
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.
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:184
QList< QgsRectangle > mLastExtent
recently used extent
Definition: qgsmapcanvas.h:561
static QgsCRSCache * instance()
Definition: qgscrscache.cpp:85
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:209
QgsMapLayer * layer()
Definition: qgsmapcanvas.h:87
void extentsChanged()
Emitted when the extents of the map change.
int renderingTime() const
Find out how log it took to finish the job (in miliseconds)
std::auto_ptr< CanvasProperties > mCanvasProperties
Handle pattern for implementation object.
Definition: qgsmapcanvas.h:507
void mouseMoveEvent(QMouseEvent *e)
Overridden mouse move event.
bool mJobCancelled
Flag determining whether the active job has been cancelled.
Definition: qgsmapcanvas.h:577
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
Q_DECL_DEPRECATED void updateMap()
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:159
void keyPressEvent(QKeyEvent *e)
Overridden key press event.
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:204
void dragEnterEvent(QDragEnterEvent *e)
Overridden drag enter event.
QgsPoint toMapPoint(double x, double y) const
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()
Emmitted when map units are changed.
QStringList layerSet() const
QgsRectangle fullExtent() const
Returns the combined exent for all layers on the map canvas.
void layersChanged()
Emitted when a new set of layers has been received.
QgsRectangle boundingBoxOfSelected()
Returns the bounding box of the selected features.
#define tr(sourceText)
void writeXML(QDomNode &theNode, QDomDocument &theDoc)
void mapToolSet(QgsMapTool *tool)
Emit map tool changed event.
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.