QGIS API Documentation  2.2.0-Valmiera
 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 "qgsmessagelog.h"
55 #include "qgsmessageviewer.h"
56 #include "qgsproject.h"
57 #include "qgsrubberband.h"
58 #include "qgsvectorlayer.h"
59 #include <math.h>
60 
63 {
64  public:
65 
67 
70 
72  QPoint mouseLastXY;
73 
76 
79 
80 };
81 
82 
83 
84 QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
85  : QGraphicsView( parent )
86  , mCanvasProperties( new CanvasProperties )
87  , mNewSize( QSize() )
88  , mPainting( false )
89  , mAntiAliasing( false )
90 {
91  setObjectName( name );
92  mScene = new QGraphicsScene();
93  setScene( mScene );
94  setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
95  setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
96  mLastExtentIndex = -1;
97  mCurrentLayer = NULL;
98  mMapOverview = NULL;
99  mMapTool = NULL;
100  mLastNonZoomMapTool = NULL;
101 
102  mBackbufferEnabled = true;
103  mDrawing = false;
104  mFrozen = false;
105  mDirty = true;
106 
108 
109  // by default, the canvas is rendered
110  mRenderFlag = true;
111 
112  setMouseTracking( true );
113  setFocusPolicy( Qt::StrongFocus );
114 
116  connect( mMapRenderer, SIGNAL( datumTransformInfoRequested( const QgsMapLayer*, const QString&, const QString& ) ),
117  this, SLOT( getDatumTransformInfo( const QgsMapLayer*, const QString& , const QString& ) ) );
118 
119  mResizeTimer = new QTimer( this );
120  connect( mResizeTimer, SIGNAL( timeout() ), this, SLOT( refresh() ) );
121 
122  // create map canvas item which will show the map
123  mMap = new QgsMapCanvasMap( this );
124  mScene->addItem( mMap );
125  mScene->update(); // porting??
126 
127  moveCanvasContents( true );
128 
129  connect( mMapRenderer, SIGNAL( drawError( QgsMapLayer* ) ), this, SLOT( showError( QgsMapLayer* ) ) );
130  connect( mMapRenderer, SIGNAL( hasCrsTransformEnabledChanged( bool ) ), this, SLOT( crsTransformEnabled( bool ) ) );
131 
133 
134  // project handling
135  connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ),
136  this, SLOT( readProject( const QDomDocument & ) ) );
137  connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ),
138  this, SLOT( writeProject( QDomDocument & ) ) );
139  mMap->resize( size() );
140 
141 #ifdef Q_OS_WIN
142  // Enable touch event on Windows.
143  // Qt on Windows needs to be told it can take touch events or else it ignores them.
144  grabGesture( Qt::PinchGesture );
145  viewport()->setAttribute( Qt::WA_AcceptTouchEvents );
146 #endif
147 } // QgsMapCanvas ctor
148 
149 
151 {
152  if ( mMapTool )
153  {
154  mMapTool->deactivate();
155  mMapTool = NULL;
156  }
157  mLastNonZoomMapTool = NULL;
158 
159  // delete canvas items prior to deleteing the canvas
160  // because they might try to update canvas when it's
161  // already being destructed, ends with segfault
162  QList<QGraphicsItem*> list = mScene->items();
163  QList<QGraphicsItem*>::iterator it = list.begin();
164  while ( it != list.end() )
165  {
166  QGraphicsItem* item = *it;
167  delete item;
168  ++it;
169  }
170 
171  mScene->deleteLater(); // crashes in python tests on windows
172 
173  delete mMapRenderer;
174  // mCanvasProperties auto-deleted via std::auto_ptr
175  // CanvasProperties struct has its own dtor for freeing resources
176 
177 } // dtor
178 
180 {
181  mAntiAliasing = theFlag;
182  mMap->enableAntiAliasing( theFlag );
183  if ( mMapOverview )
184  mMapOverview->enableAntiAliasing( theFlag );
185 } // anti aliasing
186 
187 void QgsMapCanvas::useImageToRender( bool theFlag )
188 {
189  mMap->useImageToRender( theFlag );
190  refresh(); // redraw the map on change - prevents black map view
191 }
192 
194 {
195  return mMap;
196 }
197 
199 {
200  return mMapRenderer;
201 }
202 
203 
205 {
206  QStringList& layers = mMapRenderer->layerSet();
207  if ( index >= 0 && index < ( int ) layers.size() )
208  return QgsMapLayerRegistry::instance()->mapLayer( layers[index] );
209  else
210  return NULL;
211 }
212 
213 
215 {
217 }
218 
220 {
221  return mMapRenderer->scale();
222 } // scale
223 
224 void QgsMapCanvas::setDirty( bool dirty )
225 {
226  mDirty = dirty;
227 }
228 
230 {
231  return mDirty;
232 }
233 
234 
235 
237 {
238  return mDrawing;
239 } // isDrawing
240 
241 
242 // return the current coordinate transform based on the extents and
243 // device size
245 {
247 }
248 
249 void QgsMapCanvas::setLayerSet( QList<QgsMapCanvasLayer> &layers )
250 {
251  if ( mDrawing )
252  {
253  QgsDebugMsg( "NOT updating layer set while drawing" );
254  return;
255  }
256 
257  // create layer set
258  QStringList layerSet, layerSetOverview;
259 
260  int i;
261  for ( i = 0; i < layers.size(); i++ )
262  {
263  QgsMapCanvasLayer &lyr = layers[i];
264  if ( !lyr.layer() )
265  {
266  continue;
267  }
268 
269  if ( lyr.isVisible() )
270  {
271  layerSet.push_back( lyr.layer()->id() );
272  }
273 
274  if ( lyr.isInOverview() )
275  {
276  layerSetOverview.push_back( lyr.layer()->id() );
277  }
278  }
279 
280  QStringList& layerSetOld = mMapRenderer->layerSet();
281 
282  bool layerSetChanged = layerSetOld != layerSet;
283 
284  // update only if needed
285  if ( layerSetChanged )
286  {
287  QgsDebugMsg( "Layers changed to: " + layerSet.join( ", " ) );
288 
289  for ( i = 0; i < layerCount(); i++ )
290  {
291  // Add check if vector layer when disconnecting from selectionChanged slot
292  // Ticket #811 - racicot
294  disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
295  disconnect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
296  QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
297  if ( isVectLyr )
298  {
299  disconnect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
300  }
301  }
302 
303  mMapRenderer->setLayerSet( layerSet );
304 
305  for ( i = 0; i < layerCount(); i++ )
306  {
307  // Add check if vector layer when connecting to selectionChanged slot
308  // Ticket #811 - racicot
310  connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
311  connect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
312  QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
313  if ( isVectLyr )
314  {
315  connect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
316  }
317  }
318 
319  QgsDebugMsg( "Layers have changed, refreshing" );
320  emit layersChanged();
321 
322  refresh();
323  }
324 
325  if ( mMapOverview )
326  {
327  QStringList& layerSetOvOld = mMapOverview->layerSet();
328  if ( layerSetOvOld != layerSetOverview )
329  {
330  mMapOverview->setLayerSet( layerSetOverview );
331  }
332 
333  // refresh overview maplayers even if layer set is the same
334  // because full extent might have changed
335  updateOverview();
336  }
337 } // setLayerSet
338 
340 {
341  if ( mMapOverview )
342  {
343  // disconnect old map overview if exists
344  disconnect( mMapRenderer, SIGNAL( hasCrsTransformEnabledChanged( bool ) ),
345  mMapOverview, SLOT( hasCrsTransformEnabled( bool ) ) );
346  disconnect( mMapRenderer, SIGNAL( destinationSrsChanged() ),
347  mMapOverview, SLOT( destinationSrsChanged() ) );
348 
349  // map overview is not owned by map canvas so don't delete it...
350  }
351 
352  mMapOverview = overview;
353 
354  if ( overview )
355  {
356  // connect to the map render to copy its projection settings
357  connect( mMapRenderer, SIGNAL( hasCrsTransformEnabledChanged( bool ) ),
358  overview, SLOT( hasCrsTransformEnabled( bool ) ) );
359  connect( mMapRenderer, SIGNAL( destinationSrsChanged() ),
360  overview, SLOT( destinationSrsChanged() ) );
361  }
362 }
363 
364 
366 {
367  // redraw overview
368  if ( mMapOverview )
369  {
371  }
372 }
373 
374 
376 {
377  return mCurrentLayer;
378 }
379 
380 
382 {
383  mResizeTimer->stop();
384 
385  // we can't draw again if already drawing...
386  if ( mDrawing )
387  return;
388 
389  QSettings settings;
390  bool logRefresh = settings.value( "/Map/logCanvasRefreshEvent", false ).toBool();
391  QTime t;
392  if ( logRefresh )
393  {
394  t.start();
395  }
396 
397 #ifdef Q_WS_X11
398  bool enableBackbufferSetting = settings.value( "/Map/enableBackbuffer", 1 ).toBool();
399 #endif
400 
401 #ifdef Q_WS_X11
402 #ifndef ANDROID
403  // disable the update that leads to the resize crash on X11 systems
404  if ( viewport() )
405  {
406  if ( enableBackbufferSetting != mBackbufferEnabled )
407  {
408  qDebug() << "Enable back buffering: " << enableBackbufferSetting;
409  if ( enableBackbufferSetting )
410  {
411  viewport()->setAttribute( Qt::WA_PaintOnScreen, false );
412  }
413  else
414  {
415  viewport()->setAttribute( Qt::WA_PaintOnScreen, true );
416  }
417  mBackbufferEnabled = enableBackbufferSetting;
418  }
419  }
420 #endif // ANDROID
421 #endif // Q_WS_X11
422 
423  mDrawing = true;
424 
425  //update $map variable to canvas
426  QgsExpression::setSpecialColumn( "$map", tr( "canvas" ) );
427 
428  if ( mRenderFlag && !mFrozen )
429  {
430  clear();
431 
432  // Tell the user we're going to be a while
433  QApplication::setOverrideCursor( Qt::WaitCursor );
434 
435  emit renderStarting();
436 
437  mMap->render();
438 
439  mDirty = false;
440 
441  // notify any listeners that rendering is complete
442  QPainter p;
443  p.begin( &mMap->paintDevice() );
444  emit renderComplete( &p );
445  p.end();
446 
447  // notifies current map tool
448  if ( mMapTool )
450 
451  // Tell the user we've finished going to be a while
452  QApplication::restoreOverrideCursor();
453  }
454 
455  mDrawing = false;
456 
457  // Done refreshing
458  emit mapCanvasRefreshed();
459 
460  if ( logRefresh )
461  {
462  QString logMsg = tr( "Canvas refresh: %1 ms" ).arg( t.elapsed() );
463  QObject* senderObj = QObject::sender();
464  if ( senderObj )
465  {
466  logMsg += tr( ", sender '%1'" ).arg( senderObj->metaObject()->className() );
467  }
468  QgsMessageLog::logMessage( logMsg, tr( "Rendering" ) );
469  }
470 
471 } // refresh
472 
474 {
475  if ( mMap )
476  {
477  mMap->updateContents();
478  }
479 }
480 
481 //the format defaults to "PNG" if not specified
482 void QgsMapCanvas::saveAsImage( QString theFileName, QPixmap * theQPixmap, QString theFormat )
483 {
484  //
485  //check if the optional QPaintDevice was supplied
486  //
487  if ( theQPixmap != NULL )
488  {
489  // render
490  QPainter painter;
491  painter.begin( theQPixmap );
492  mMapRenderer->render( &painter );
493  emit renderComplete( &painter );
494  painter.end();
495 
496  theQPixmap->save( theFileName, theFormat.toLocal8Bit().data() );
497  }
498  else //use the map view
499  {
500  QPixmap *pixmap = dynamic_cast<QPixmap *>( &mMap->paintDevice() );
501  if ( !pixmap )
502  return;
503 
504  pixmap->save( theFileName, theFormat.toLocal8Bit().data() );
505  }
506  //create a world file to go with the image...
507  QgsRectangle myRect = mMapRenderer->extent();
508  QString myHeader;
509  // note: use 17 places of precision for all numbers output
510  //Pixel XDim
511  myHeader += qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
512  //Rotation on y axis - hard coded
513  myHeader += "0 \r\n";
514  //Rotation on x axis - hard coded
515  myHeader += "0 \r\n";
516  //Pixel YDim - almost always negative - see
517  //http://en.wikipedia.org/wiki/World_file#cite_note-2
518  myHeader += "-" + qgsDoubleToString( mapUnitsPerPixel() ) + "\r\n";
519  //Origin X (center of top left cell)
520  myHeader += qgsDoubleToString( myRect.xMinimum() + ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
521  //Origin Y (center of top left cell)
522  myHeader += qgsDoubleToString( myRect.yMaximum() - ( mapUnitsPerPixel() / 2 ) ) + "\r\n";
523  QFileInfo myInfo = QFileInfo( theFileName );
524  // allow dotted names
525  QString myWorldFileName = myInfo.absolutePath() + "/" + myInfo.completeBaseName() + "." + theFormat + "w";
526  QFile myWorldFile( myWorldFileName );
527  if ( !myWorldFile.open( QIODevice::WriteOnly ) ) //don't use QIODevice::Text
528  {
529  return;
530  }
531  QTextStream myStream( &myWorldFile );
532  myStream << myHeader;
533 } // saveAsImage
534 
535 
536 
538 {
539  return mMapRenderer->extent();
540 } // extent
541 
543 {
544  return mMapRenderer->fullExtent();
545 } // extent
546 
548 {
549  // projection settings have changed
550 
551  QgsDebugMsg( "updating full extent" );
552 
554  refresh();
555 }
556 
558 {
559  if ( mDrawing )
560  {
561  return;
562  }
563 
564  QgsRectangle current = extent();
565 
566  if ( r.isEmpty() )
567  {
568  QgsDebugMsg( "Empty extent - keeping old extent with new center!" );
569  QgsRectangle e( QgsPoint( r.center().x() - current.width() / 2.0, r.center().y() - current.height() / 2.0 ),
570  QgsPoint( r.center().x() + current.width() / 2.0, r.center().y() + current.height() / 2.0 ) );
571  mMapRenderer->setExtent( e );
572  }
573  else
574  {
575  mMapRenderer->setExtent( r );
576  }
577  emit extentsChanged();
578  updateScale();
579  if ( mMapOverview )
581  if ( mLastExtent.size() > 20 )
582  mLastExtent.removeAt( 0 );
583 
584  //clear all extent items after current index
585  for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
586  {
587  mLastExtent.removeAt( i );
588  }
589 
590  mLastExtent.append( extent() ) ;
591 
592  // adjust history to no more than 20
593  if ( mLastExtent.size() > 20 )
594  {
595  mLastExtent.removeAt( 0 );
596  }
597 
598  // the last item is the current extent
599  mLastExtentIndex = mLastExtent.size() - 1;
600 
601  // update controls' enabled state
602  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
603  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
604  // notify canvas items of change
606 
607 } // setExtent
608 
609 
611 {
612  double scale = mMapRenderer->scale();
613 
614  emit scaleChanged( scale );
615 }
616 
617 
619 {
620  // Indicate to the next paint event that we need to rebuild the canvas contents
621  setDirty( true );
622 
623 } // clear
624 
625 
626 
628 {
629  if ( mDrawing )
630  {
631  return;
632  }
633 
635  // If the full extent is an empty set, don't do the zoom
636  if ( !extent.isEmpty() )
637  {
638  // Add a 5% margin around the full extent
639  extent.scale( 1.05 );
640  setExtent( extent );
641  }
642  refresh();
643 
644 } // zoomToFullExtent
645 
646 
647 
649 {
650  if ( mDrawing )
651  {
652  return;
653  }
654 
655  if ( mLastExtentIndex > 0 )
656  {
659  emit extentsChanged();
660  updateScale();
661  if ( mMapOverview )
663  refresh();
664  // update controls' enabled state
665  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
666  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
667  // notify canvas items of change
669  }
670 
671 } // zoomToPreviousExtent
672 
674 {
675  if ( mDrawing )
676  {
677  return;
678  }
679  if ( mLastExtentIndex < mLastExtent.size() - 1 )
680  {
683  emit extentsChanged();
684  updateScale();
685  if ( mMapOverview )
687  refresh();
688  // update controls' enabled state
689  emit zoomLastStatusChanged( mLastExtentIndex > 0 );
690  emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
691  // notify canvas items of change
693  }
694 }// zoomToNextExtent
695 
697 {
698  mLastExtent.clear(); // clear the zoom history list
699  mLastExtent.append( extent() ) ; // set the current extent in the list
700  mLastExtentIndex = mLastExtent.size() - 1;
701  // update controls' enabled state
704 }// clearExtentHistory
705 
706 
708 {
710 }
711 
713 {
714  // We assume that if the map units have changed, the changed value
715  // will be accessible from QgsMapRenderer
716 
717  // And then force a redraw of the scale number in the status bar
718  updateScale();
719 
720  // And then redraw the map to force the scale bar to update
721  // itself. This is less than ideal as the entire map gets redrawn
722  // just to get the scale bar to redraw itself. If we ask the scale
723  // bar to redraw itself without redrawing the map, the existing
724  // scale bar is not removed, and we end up with two scale bars in
725  // the same location. This can perhaps be fixed when/if the scale
726  // bar is done as a transparent layer on top of the map canvas.
727  refresh();
728 }
729 
731 {
732  if ( mDrawing )
733  {
734  return;
735  }
736 
737  if ( layer == NULL )
738  {
739  // use current layer by default
740  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
741  }
742 
743  if ( layer == NULL )
744  {
745  return;
746  }
747 
748  if ( layer->selectedFeatureCount() == 0 )
749  {
750  return;
751  }
752 
754 
755  // no selected features, only one selected point feature
756  //or two point features with the same x- or y-coordinates
757  if ( rect.isEmpty() )
758  {
759  // zoom in
760  QgsPoint c = rect.center();
761  rect = extent();
762  rect.scale( 1.0, &c );
763  }
764  //zoom to an area
765  else
766  {
767  // Expand rect to give a bit of space around the selected
768  // objects so as to keep them clear of the map boundaries
769  // The same 5% should apply to all margins.
770  rect.scale( 1.05 );
771  }
772 
773  setExtent( rect );
774  refresh();
775 } // zoomToSelected
776 
778 {
779  if ( mDrawing )
780  {
781  return;
782  }
783 
784  if ( layer == NULL )
785  {
786  // use current layer by default
787  layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
788  }
789 
790  if ( layer == NULL )
791  {
792  return;
793  }
794 
795  if ( layer->selectedFeatureCount() == 0 )
796  {
797  return;
798  }
799 
801  setExtent( QgsRectangle( rect.center(), rect.center() ) );
802  refresh();
803 } // panToSelected
804 
805 void QgsMapCanvas::keyPressEvent( QKeyEvent * e )
806 {
807 
808  if ( mDrawing )
809  {
810  e->ignore();
811  }
812 
813  if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
814  {
815  emit keyPressed( e );
816  return;
817  }
818 
819  QPainter paint;
820  QPen pen( Qt::gray );
821  QgsPoint ll, ur;
822 
823  if ( ! mCanvasProperties->mouseButtonDown )
824  {
825  // Don't want to interfer with mouse events
826 
827  QgsRectangle currentExtent = mMapRenderer->extent();
828  double dx = qAbs(( currentExtent.xMaximum() - currentExtent.xMinimum() ) / 4 );
829  double dy = qAbs(( currentExtent.yMaximum() - currentExtent.yMinimum() ) / 4 );
830 
831  switch ( e->key() )
832  {
833  case Qt::Key_Left:
834  QgsDebugMsg( "Pan left" );
835 
836  currentExtent.setXMinimum( currentExtent.xMinimum() - dx );
837  currentExtent.setXMaximum( currentExtent.xMaximum() - dx );
838  setExtent( currentExtent );
839  refresh();
840  break;
841 
842  case Qt::Key_Right:
843  QgsDebugMsg( "Pan right" );
844 
845  currentExtent.setXMinimum( currentExtent.xMinimum() + dx );
846  currentExtent.setXMaximum( currentExtent.xMaximum() + dx );
847  setExtent( currentExtent );
848  refresh();
849  break;
850 
851  case Qt::Key_Up:
852  QgsDebugMsg( "Pan up" );
853 
854  currentExtent.setYMaximum( currentExtent.yMaximum() + dy );
855  currentExtent.setYMinimum( currentExtent.yMinimum() + dy );
856  setExtent( currentExtent );
857  refresh();
858  break;
859 
860  case Qt::Key_Down:
861  QgsDebugMsg( "Pan down" );
862 
863  currentExtent.setYMaximum( currentExtent.yMaximum() - dy );
864  currentExtent.setYMinimum( currentExtent.yMinimum() - dy );
865  setExtent( currentExtent );
866  refresh();
867  break;
868 
869 
870 
871  case Qt::Key_Space:
872  QgsDebugMsg( "Pressing pan selector" );
873 
874  //mCanvasProperties->dragging = true;
875  if ( ! e->isAutoRepeat() )
876  {
877  mCanvasProperties->panSelectorDown = true;
878  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
879  }
880  break;
881 
882  case Qt::Key_PageUp:
883  QgsDebugMsg( "Zoom in" );
884  zoomIn();
885  break;
886 
887  case Qt::Key_PageDown:
888  QgsDebugMsg( "Zoom out" );
889  zoomOut();
890  break;
891 
892  default:
893  // Pass it on
894  if ( mMapTool )
895  {
896  mMapTool->keyPressEvent( e );
897  }
898  else e->ignore();
899 
900  QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
901  }
902  }
903 
904  emit keyPressed( e );
905 
906 } //keyPressEvent()
907 
908 void QgsMapCanvas::keyReleaseEvent( QKeyEvent * e )
909 {
910  QgsDebugMsg( "keyRelease event" );
911 
912  if ( mDrawing )
913  {
914  return;
915  }
916 
917  switch ( e->key() )
918  {
919  case Qt::Key_Space:
920  if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
921  {
922  QgsDebugMsg( "Releasing pan selector" );
923 
924  mCanvasProperties->panSelectorDown = false;
925  panActionEnd( mCanvasProperties->mouseLastXY );
926  }
927  break;
928 
929  default:
930  // Pass it on
931  if ( mMapTool )
932  {
934  }
935  else e->ignore();
936 
937  QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
938  }
939 
940  emit keyReleased( e );
941 
942 } //keyReleaseEvent()
943 
944 
945 void QgsMapCanvas::mouseDoubleClickEvent( QMouseEvent * e )
946 {
947  if ( mDrawing )
948  {
949  return;
950  }
951 
952  // call handler of current map tool
953  if ( mMapTool )
955 } // mouseDoubleClickEvent
956 
957 
958 void QgsMapCanvas::mousePressEvent( QMouseEvent * e )
959 {
960  if ( mDrawing )
961  {
962  return;
963  }
964 
965  //use middle mouse button for panning, map tools won't receive any events in that case
966  if ( e->button() == Qt::MidButton )
967  {
968  mCanvasProperties->panSelectorDown = true;
969  mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
970  }
971  else
972  {
973 
974  // call handler of current map tool
975  if ( mMapTool )
977  }
978 
979  if ( mCanvasProperties->panSelectorDown )
980  {
981  return;
982  }
983 
984  mCanvasProperties->mouseButtonDown = true;
985  mCanvasProperties->rubberStartPoint = e->pos();
986 
987 } // mousePressEvent
988 
989 
990 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent * e )
991 {
992  if ( mDrawing )
993  {
994  return;
995  }
996 
997  //use middle mouse button for panning, map tools won't receive any events in that case
998  if ( e->button() == Qt::MidButton )
999  {
1000  mCanvasProperties->panSelectorDown = false;
1001  panActionEnd( mCanvasProperties->mouseLastXY );
1002  }
1003  else
1004  {
1005  // call handler of current map tool
1006  if ( mMapTool )
1007  {
1008  // right button was pressed in zoom tool? return to previous non zoom tool
1009  if ( e->button() == Qt::RightButton && mMapTool->isTransient() )
1010  {
1011  QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
1012  QString( mLastNonZoomMapTool ? "not null." : "null." ) );
1013 
1014  QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
1015 
1016  // change to older non-zoom tool
1017  if ( mLastNonZoomMapTool
1018  && ( !mLastNonZoomMapTool->isEditTool() || ( vlayer && vlayer->isEditable() ) ) )
1019  {
1021  mLastNonZoomMapTool = NULL;
1022  setMapTool( t );
1023  }
1024  return;
1025  }
1027  }
1028  }
1029 
1030 
1031  mCanvasProperties->mouseButtonDown = false;
1032 
1033  if ( mCanvasProperties->panSelectorDown )
1034  return;
1035 
1036 } // mouseReleaseEvent
1037 
1038 void QgsMapCanvas::resizeEvent( QResizeEvent * e )
1039 {
1040  mNewSize = e->size();
1041  mResizeTimer->start( 500 );
1042 }
1043 
1044 void QgsMapCanvas::paintEvent( QPaintEvent *e )
1045 {
1046  if ( mNewSize.isValid() )
1047  {
1048  if ( mPainting || mDrawing || mResizeTimer->isActive() )
1049  {
1050  //cancel current render progress
1051  if ( mMapRenderer )
1052  {
1053  QgsRenderContext* theRenderContext = mMapRenderer->rendererContext();
1054  if ( theRenderContext )
1055  {
1056  theRenderContext->setRenderingStopped( true );
1057  }
1058  }
1059  return;
1060  }
1061 
1062  mPainting = true;
1063 
1064  while ( mNewSize.isValid() )
1065  {
1066  QSize lastSize = mNewSize;
1067  mNewSize = QSize();
1068 
1069  //set map size before scene size helps keep scene indexes updated properly
1070  // this was the cause of rubberband artifacts
1071  mMap->resize( lastSize );
1072  mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1073 
1074  // notify canvas items of change
1076 
1077  updateScale();
1078 
1079  refresh();
1080 
1081  emit extentsChanged();
1082  }
1083 
1084  mPainting = false;
1085  }
1086 
1087  QGraphicsView::paintEvent( e );
1088 } // paintEvent
1089 
1091 {
1092  QList<QGraphicsItem*> list = mScene->items();
1093  QList<QGraphicsItem*>::iterator it = list.begin();
1094  while ( it != list.end() )
1095  {
1096  QgsMapCanvasItem* item = dynamic_cast<QgsMapCanvasItem *>( *it );
1097 
1098  if ( item )
1099  {
1100  item->updatePosition();
1101  }
1102 
1103  ++it;
1104  }
1105 }
1106 
1107 
1108 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
1109 {
1110  // Zoom the map canvas in response to a mouse wheel event. Moving the
1111  // wheel forward (away) from the user zooms in
1112 
1113  QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
1114 
1115  if ( mDrawing )
1116  {
1117  return;
1118  }
1119 
1120  if ( mMapTool )
1121  {
1122  mMapTool->wheelEvent( e );
1123  }
1124 
1125  if ( QgsApplication::keyboardModifiers() )
1126  {
1127  // leave the wheel for map tools if any modifier pressed
1128  return;
1129  }
1130 
1131  switch ( mWheelAction )
1132  {
1133  case WheelZoom:
1134  // zoom without changing extent
1135  if ( e->delta() > 0 )
1136  zoomIn();
1137  else
1138  zoomOut();
1139  break;
1140 
1141  case WheelZoomAndRecenter:
1142  // zoom and don't change extent
1143  zoomWithCenter( e->x(), e->y(), e->delta() > 0 );
1144  break;
1145 
1147  {
1148  // zoom map to mouse cursor
1149  double scaleFactor = e->delta() > 0 ? 1 / mWheelZoomFactor : mWheelZoomFactor;
1150 
1151  QgsPoint oldCenter( mMapRenderer->extent().center() );
1152  QgsPoint mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
1153  QgsPoint newCenter( mousePos.x() + (( oldCenter.x() - mousePos.x() ) * scaleFactor ),
1154  mousePos.y() + (( oldCenter.y() - mousePos.y() ) * scaleFactor ) );
1155 
1156  // same as zoomWithCenter (no coordinate transformations are needed)
1158  extent.scale( scaleFactor, &newCenter );
1159  setExtent( extent );
1160  refresh();
1161  break;
1162  }
1163 
1164  case WheelNothing:
1165  // well, nothing!
1166  break;
1167  }
1168 }
1169 
1170 void QgsMapCanvas::setWheelAction( WheelAction action, double factor )
1171 {
1172  mWheelAction = action;
1173  mWheelZoomFactor = factor;
1174 }
1175 
1177 {
1179 }
1180 
1182 {
1184 }
1185 
1186 void QgsMapCanvas::zoomScale( double newScale )
1187 {
1188  zoomByFactor( newScale / scale() );
1189 }
1190 
1191 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
1192 {
1193  if ( mDrawing )
1194  {
1195  return;
1196  }
1197 
1198  double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1199 
1200  // transform the mouse pos to map coordinates
1201  QgsPoint center = getCoordinateTransform()->toMapPoint( x, y );
1203  r.scale( scaleFactor, &center );
1204  setExtent( r );
1205  refresh();
1206 }
1207 
1208 void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
1209 {
1210  if ( mDrawing )
1211  {
1212  return;
1213  }
1214 
1215  mCanvasProperties->mouseLastXY = e->pos();
1216 
1217  if ( mCanvasProperties->panSelectorDown )
1218  {
1219  panAction( e );
1220  }
1221  else
1222  {
1223  // call handler of current map tool
1224  if ( mMapTool )
1225  mMapTool->canvasMoveEvent( e );
1226  }
1227 
1228  // show x y on status bar
1229  QPoint xy = e->pos();
1231  emit xyCoordinates( coord );
1232 } // mouseMoveEvent
1233 
1234 
1235 
1238 {
1239  if ( !tool )
1240  return;
1241 
1242  if ( mMapTool )
1243  {
1244  disconnect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1245  mMapTool->deactivate();
1246  }
1247 
1248  if ( tool->isTransient() && mMapTool && !mMapTool->isTransient() )
1249  {
1250  // if zoom or pan tool will be active, save old tool
1251  // to bring it back on right click
1252  // (but only if it wasn't also zoom or pan tool)
1254  }
1255  else
1256  {
1257  mLastNonZoomMapTool = NULL;
1258  }
1259 
1260  // set new map tool and activate it
1261  mMapTool = tool;
1262  if ( mMapTool )
1263  {
1264  connect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
1265  mMapTool->activate();
1266  }
1267 
1268  emit mapToolSet( mMapTool );
1269 } // setMapTool
1270 
1272 {
1273  if ( mMapTool && mMapTool == tool )
1274  {
1275  mMapTool->deactivate();
1276  mMapTool = NULL;
1277  emit mapToolSet( NULL );
1278  setCursor( Qt::ArrowCursor );
1279  }
1280 
1281  if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1282  {
1283  mLastNonZoomMapTool = NULL;
1284  }
1285 }
1286 
1288 void QgsMapCanvas::setCanvasColor( const QColor & theColor )
1289 {
1290  // background of map's pixmap
1291  mMap->setBackgroundColor( theColor );
1292 
1293  // background of the QGraphicsView
1294  QBrush bgBrush( theColor );
1295  setBackgroundBrush( bgBrush );
1296 #if 0
1297  QPalette palette;
1298  palette.setColor( backgroundRole(), theColor );
1299  setPalette( palette );
1300 #endif
1301 
1302  // background of QGraphicsScene
1303  mScene->setBackgroundBrush( bgBrush );
1304 } // setBackgroundColor
1305 
1307 {
1308  return mScene->backgroundBrush().color();
1309 }
1310 
1312 {
1313  return mMapRenderer->layerSet().size();
1314 } // layerCount
1315 
1316 
1317 QList<QgsMapLayer*> QgsMapCanvas::layers() const
1318 {
1319  QList<QgsMapLayer*> lst;
1320  foreach ( QString layerID, mMapRenderer->layerSet() )
1321  {
1323  if ( layer )
1324  lst.append( layer );
1325  }
1326  return lst;
1327 }
1328 
1329 
1331 {
1332  // called when a layer has changed visibility setting
1333 
1334  refresh();
1335 
1336 } // layerStateChange
1337 
1338 
1339 
1340 void QgsMapCanvas::freeze( bool frz )
1341 {
1342  mFrozen = frz;
1343 } // freeze
1344 
1346 {
1347  return mFrozen;
1348 } // freeze
1349 
1350 
1352 {
1353  return mMap->paintDevice();
1354 }
1355 
1357 {
1358  return mMapRenderer->mapUnitsPerPixel();
1359 } // mapUnitsPerPixel
1360 
1361 
1363 {
1364  QgsDebugMsg( "Setting map units to " + QString::number( static_cast<int>( u ) ) );
1365  mMapRenderer->setMapUnits( u );
1366 }
1367 
1368 
1370 {
1371  return mMapRenderer->mapUnits();
1372 }
1373 
1374 
1375 void QgsMapCanvas::setRenderFlag( bool theFlag )
1376 {
1377  mRenderFlag = theFlag;
1378  if ( mMapRenderer )
1379  {
1381  if ( rc )
1382  {
1383  rc->setRenderingStopped( !theFlag );
1384  }
1385  }
1386 
1387  if ( mRenderFlag )
1388  {
1389  refresh();
1390  }
1391 }
1392 
1393 void QgsMapCanvas::connectNotify( const char * signal )
1394 {
1395  Q_UNUSED( signal );
1396  QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
1397 } //connectNotify
1398 
1399 
1400 
1402 {
1403  return mMapTool;
1404 }
1405 
1406 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
1407 {
1408  if ( mDrawing )
1409  {
1410  return;
1411  }
1412 
1413  // move map image and other items to standard position
1414  moveCanvasContents( true ); // true means reset
1415 
1416  // use start and end box points to calculate the extent
1417  QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
1418  QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );
1419 
1420  double dx = qAbs( end.x() - start.x() );
1421  double dy = qAbs( end.y() - start.y() );
1422 
1423  // modify the extent
1425 
1426  if ( end.x() < start.x() )
1427  {
1428  r.setXMinimum( r.xMinimum() + dx );
1429  r.setXMaximum( r.xMaximum() + dx );
1430  }
1431  else
1432  {
1433  r.setXMinimum( r.xMinimum() - dx );
1434  r.setXMaximum( r.xMaximum() - dx );
1435  }
1436 
1437  if ( end.y() < start.y() )
1438  {
1439  r.setYMaximum( r.yMaximum() + dy );
1440  r.setYMinimum( r.yMinimum() + dy );
1441 
1442  }
1443  else
1444  {
1445  r.setYMaximum( r.yMaximum() - dy );
1446  r.setYMinimum( r.yMinimum() - dy );
1447 
1448  }
1449 
1450  setExtent( r );
1451  refresh();
1452 }
1453 
1454 void QgsMapCanvas::panAction( QMouseEvent * e )
1455 {
1456  Q_UNUSED( e );
1457 
1458  if ( mDrawing )
1459  {
1460  return;
1461  }
1462 
1463  // move all map canvas items
1465 
1466  // update canvas
1467  //updateContents(); // TODO: need to update?
1468 }
1469 
1471 {
1472  if ( mDrawing )
1473  {
1474  return;
1475  }
1476 
1477  QPoint pnt( 0, 0 );
1478  if ( !reset )
1479  pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
1480 
1481  mMap->setPanningOffset( pnt );
1482 
1483  QList<QGraphicsItem*> list = mScene->items();
1484  QList<QGraphicsItem*>::iterator it = list.begin();
1485  while ( it != list.end() )
1486  {
1487  QGraphicsItem* item = *it;
1488 
1489  if ( item != mMap )
1490  {
1491  // this tells map canvas item to draw with offset
1492  QgsMapCanvasItem* canvasItem = dynamic_cast<QgsMapCanvasItem *>( item );
1493  if ( canvasItem )
1494  canvasItem->setPanningOffset( pnt );
1495  }
1496 
1497  ++it;
1498  }
1499 
1500  // show items
1502 
1503 }
1504 
1506 {
1507 #if 0
1508  QMessageBox::warning(
1509  this,
1510  mapLayer->lastErrorTitle(),
1511  tr( "Could not draw %1 because:\n%2", "COMMENTED OUT" ).arg( mapLayer->name() ).arg( mapLayer->lastError() )
1512  );
1513 #endif
1514 
1515  QgsMessageViewer * mv = new QgsMessageViewer( this );
1516  mv->setWindowTitle( mapLayer->lastErrorTitle() );
1517  mv->setMessageAsPlainText( tr( "Could not draw %1 because:\n%2" )
1518  .arg( mapLayer->name() ).arg( mapLayer->lastError() ) );
1519  mv->exec();
1520  //MH
1521  //QgsMessageViewer automatically sets delete on close flag
1522  //so deleting mv would lead to a segfault
1523 }
1524 
1526 {
1527  return mCanvasProperties->mouseLastXY;
1528 }
1529 
1530 void QgsMapCanvas::readProject( const QDomDocument & doc )
1531 {
1532  QDomNodeList nodes = doc.elementsByTagName( "mapcanvas" );
1533  if ( nodes.count() )
1534  {
1535  QDomNode node = nodes.item( 0 );
1536  mMapRenderer->readXML( node );
1537  clearExtentHistory(); // clear the extent history on project load
1538  }
1539  else
1540  {
1541  QgsDebugMsg( "Couldn't read mapcanvas information from project" );
1542  }
1543 }
1544 
1545 void QgsMapCanvas::writeProject( QDomDocument & doc )
1546 {
1547  // create node "mapcanvas" and call mMapRenderer->writeXML()
1548 
1549  QDomNodeList nl = doc.elementsByTagName( "qgis" );
1550  if ( !nl.count() )
1551  {
1552  QgsDebugMsg( "Unable to find qgis element in project file" );
1553  return;
1554  }
1555  QDomNode qgisNode = nl.item( 0 ); // there should only be one, so zeroth element ok
1556 
1557  QDomElement mapcanvasNode = doc.createElement( "mapcanvas" );
1558  qgisNode.appendChild( mapcanvasNode );
1559  mMapRenderer->writeXML( mapcanvasNode, doc );
1560 }
1561 
1563 void QgsMapCanvas::getDatumTransformInfo( const QgsMapLayer* ml, const QString& srcAuthId, const QString& destAuthId )
1564 {
1565  if ( !ml )
1566  {
1567  return;
1568  }
1569 
1570  //check if default datum transformation available
1571  QSettings s;
1572  QString settingsString = "/Projections/" + srcAuthId + "//" + destAuthId;
1573  QVariant defaultSrcTransform = s.value( settingsString + "_srcTransform" );
1574  QVariant defaultDestTransform = s.value( settingsString + "_destTransform" );
1575  if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
1576  {
1577  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, defaultSrcTransform.toInt(), defaultDestTransform.toInt() );
1578  return;
1579  }
1580 
1581  const QgsCoordinateReferenceSystem& srcCRS = QgsCRSCache::instance()->crsByAuthId( srcAuthId );
1582  const QgsCoordinateReferenceSystem& destCRS = QgsCRSCache::instance()->crsByAuthId( destAuthId );
1583 
1584  if ( !s.value( "/Projections/showDatumTransformDialog", false ).toBool() )
1585  {
1586  // just use the default transform
1587  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, -1, -1 );
1588  return;
1589  }
1590 
1591  //get list of datum transforms
1592  QList< QList< int > > dt = QgsCoordinateTransform::datumTransformations( srcCRS, destCRS );
1593  if ( dt.size() < 2 )
1594  {
1595  return;
1596  }
1597 
1598  //if several possibilities: present dialog
1599  QgsDatumTransformDialog d( ml->name(), dt );
1600  if ( mMapRenderer && ( d.exec() == QDialog::Accepted ) )
1601  {
1602  int srcTransform = -1;
1603  int destTransform = -1;
1604  QList<int> t = d.selectedDatumTransform();
1605  if ( t.size() > 0 )
1606  {
1607  srcTransform = t.at( 0 );
1608  }
1609  if ( t.size() > 1 )
1610  {
1611  destTransform = t.at( 1 );
1612  }
1613  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, srcTransform, destTransform );
1614  if ( d.rememberSelection() )
1615  {
1616  s.setValue( settingsString + "_srcTransform", srcTransform );
1617  s.setValue( settingsString + "_destTransform", destTransform );
1618  }
1619  }
1620  else
1621  {
1622  mMapRenderer->addLayerCoordinateTransform( ml->id(), srcAuthId, destAuthId, -1, -1 );
1623  }
1624 }
1625 
1626 void QgsMapCanvas::zoomByFactor( double scaleFactor )
1627 {
1628  if ( mDrawing )
1629  {
1630  return;
1631  }
1632 
1634  r.scale( scaleFactor );
1635  setExtent( r );
1636  refresh();
1637 }
1638 
1640 {
1641  // Find out which layer it was that sent the signal.
1642  QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
1643  emit selectionChanged( layer );
1644  refresh();
1645 }
1646 
1647 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent * e )
1648 {
1649  // By default graphics view delegates the drag events to graphics items.
1650  // But we do not want that and by ignoring the drag enter we let the
1651  // parent (e.g. QgisApp) to handle drops of map layers etc.
1652  e->ignore();
1653 }
1654 
1656 {
1657  if ( enabled )
1658  {
1659  QgsDebugMsg( "refreshing after reprojection was enabled" );
1660  refresh();
1661  connect( mMapRenderer, SIGNAL( destinationSrsChanged() ), this, SLOT( refresh() ) );
1662  }
1663  else
1664  disconnect( mMapRenderer, SIGNAL( destinationSrsChanged() ), this, SLOT( refresh() ) );
1665 }
1666 
1668 {
1669  QgsDebugMsg( "maptool destroyed" );
1670  mMapTool = 0;
1671 }
1672 
1673 #ifdef HAVE_TOUCH
1674 bool QgsMapCanvas::event( QEvent * e )
1675 {
1676  bool done = false;
1677  if ( mDrawing )
1678  {
1679  return done;
1680  }
1681  if ( e->type() == QEvent::Gesture )
1682  {
1683  // call handler of current map tool
1684  if ( mMapTool )
1685  {
1686  done = mMapTool->gestureEvent( static_cast<QGestureEvent*>( e ) );
1687  }
1688  }
1689  else
1690  {
1691  // pass other events to base class
1692  done = QGraphicsView::event( e );
1693  }
1694  return done;
1695 }
1696 #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:438
const QgsMapToPixel * coordinateTransform()
void zoomToSelected(QgsVectorLayer *layer=NULL)
Zoom to the extent of the selected features of current (vector) layer.
void updateCanvasItemPositions()
called on resize or changed extent to notify canvas items to change their rectangle ...
static unsigned index
QPoint mouseLastXY
Last seen point of the mouse.
void setRenderingStopped(bool stopped)
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:45
void render(QPainter *painter, double *forceWidthScale=0)
starts rendering @ param forceWidthScale Force a specific scale factor for line widths and marker siz...
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:474
void zoomWithCenter(int x, int y, bool zoomIn)
Zooms in/out with a given center.
bool isDirty() const
Return the state of the canvas (dirty or not)
void freeze(bool frz=true)
QgsRenderContext * rendererContext()
Accessor for render context.
virtual void setCanvasColor(const QColor &_newVal)
Write property of QColor bgColor.
void enableOverviewMode(QgsMapOverviewCanvas *overview)
QTimer * mResizeTimer
Definition: qgsmapcanvas.h:501
double mapUnitsPerPixel() const
Returns the mapUnitsPerPixel (map units per pixel) for the canvas.
int layerCount() const
return number of layers on the map
A widget that displays an overview map.
void setXMaximum(double x)
Set the maximum x value.
Definition: qgsrectangle.h:164
void clearExtentHistory()
void resize(QSize size)
resize canvas item and pixmap
QgsMapRenderer * mMapRenderer
all map rendering is done in this class
Definition: qgsmapcanvas.h:435
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.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:189
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
virtual void canvasMoveEvent(QMouseEvent *e)
Mouse move event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:119
virtual QString lastError()
If an operation returns 0 (e.g.
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:297
void addLayerCoordinateTransform(const QString &layerId, const QString &srcAuthId, const QString &destAuthId, int srcDatumTransform=-1, int destDatumTransform=-1)
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:69
bool hasCrsTransformEnabled()
A simple helper method to find out if on the fly projections are enabled or not.
void setCurrentLayer(QgsMapLayer *layer)
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:490
bool isVisible() const
Definition: qgsmapcanvas.h:78
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:441
void refresh()
Repaints the canvas map.
void renderComplete(QPainter *)
Emitted when the canvas has rendered.
~QgsMapCanvas()
Destructor.
void keyReleaseEvent(QKeyEvent *e)
Overridden key release event.
QgsMapTool * mapTool()
Returns the currently active tool.
void setPanningOffset(const QPoint &point)
sets current offset, to be called from QgsMapCanvas
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:124
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:129
void updateContents()
Update contents - can be called while drawing to show the status.
void resizeEvent(QResizeEvent *e)
Overridden resize event.
QgsMapTool * mMapTool
pointer to current map tool
Definition: qgsmapcanvas.h:477
double x() const
Definition: qgspoint.h:110
void zoomLastStatusChanged(bool)
Emitted when zoom last status changed.
virtual void renderComplete()
Called when rendering has finished. Default implementation does nothing.
Definition: qgsmaptool.cpp:162
bool mAntiAliasing
indicates whether antialiasing will be used for rendering
Definition: qgsmapcanvas.h:499
static void logMessage(QString message, QString tag=QString::null, MessageLevel level=WARNING)
add a message to the instance (and create it if necessary)
void updateScale()
Emits signal scaleChanged to update scale in main window.
void mouseDoubleClickEvent(QMouseEvent *e)
Overridden mouse double click event.
QgsMapLayer * mCurrentLayer
current layer in legend
Definition: qgsmapcanvas.h:471
QSize mNewSize
resize canvas size
Definition: qgsmapcanvas.h:493
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:71
void paintEvent(QPaintEvent *e)
Overridden paint event.
Perform transforms between map coordinates and device coordinates.
Definition: qgsmaptopixel.h:33
virtual void keyReleaseEvent(QKeyEvent *e)
Key event for overriding.
Definition: qgsmaptool.cpp:149
void showError(QgsMapLayer *mapLayer)
show whatever error is exposed by the QgsMapLayer.
A rectangular graphics item representing the map on the canvas.
void clear()
Clear the map canvas.
int mLastExtentIndex
Definition: qgsmapcanvas.h:484
void mapCanvasRefreshed()
Emitted when canvas finished a refresh request.
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
bool mBackbufferEnabled
If backbuffering is currently enabled.
Definition: qgsmapcanvas.h:444
void setBackgroundColor(const QColor &color)
void zoomNextStatusChanged(bool)
Emitted when zoom next status changed.
QgsMapTool * mLastNonZoomMapTool
previous tool if current is for zooming/panning
Definition: qgsmapcanvas.h:480
bool hasCrsTransformEnabled() const
returns true if projections are enabled for this layer set
void mousePressEvent(QMouseEvent *e)
Overridden mouse press event.
double mapUnitsPerPixel() const
void render()
renders map using QgsMapRenderer to mPixmap
bool mDirty
Flag to track the state of the Map canvas.
Definition: qgsmapcanvas.h:460
void panToSelected(QgsVectorLayer *layer=NULL)
Pan to the selected features of current (vector) layer keeping same extent.
void setLayerSet(QList< QgsMapCanvasLayer > &layers)
void setYMinimum(double y)
Set the minimum y value.
Definition: qgsrectangle.h:169
double scale() const
Scale denominator.
void keyReleased(QKeyEvent *e)
Emit key release event.
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
QPaintDevice & canvasPaintDevice()
Accessor for the canvas paint device.
void setMessageAsPlainText(const QString &msg)
bool mPainting
currently in paint event
Definition: qgsmapcanvas.h:496
QString id() const
Get this layer's unique ID, this ID is used to access this layer from map layer registry.
Definition: qgsmaplayer.cpp:94
void wheelEvent(QWheelEvent *e)
Overridden mouse wheel event.
virtual QString lastErrorTitle()
If an operation returns 0 (e.g.
void setRenderFlag(bool theFlag)
Whether to suppress rendering or not.
QGis::UnitType mapUnits() const
Get the current canvas map units.
virtual void deactivate()
called when map tool is being deactivated
Definition: qgsmaptool.cpp:85
virtual bool isEditTool()
Check whether this MapTool performs an edit operation.
Definition: qgsmaptool.cpp:171
QgsMapCanvasMap * map()
virtual void wheelEvent(QWheelEvent *e)
Mouse wheel event for overriding.
Definition: qgsmaptool.cpp:139
void refresh()
renders overview and updates panning widget
void renderStarting()
Emitted when the canvas is about to be rendered.
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.
void updateFullExtent()
updates extent of the layer set
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()
true if canvas currently drawing
bool writeXML(QDomNode &theNode, QDomDocument &theDoc)
write settings
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:144
QgsPoint toMapCoordinates(int x, int y) const
bool mDrawing
Flag indicating a map refresh is in progress.
Definition: qgsmapcanvas.h:446
Abstract base class for all map tools.
Definition: qgsmaptool.h:46
void selectionChangedSlot()
Receives signal about selection change, and pass it on with layer info.
double mWheelZoomFactor
Scale factor multiple for default zoom in/out.
Definition: qgsmapcanvas.h:487
bool mFrozen
Flag indicating if the map canvas is frozen.
Definition: qgsmapcanvas.h:449
QgsRectangle fullExtent()
returns current extent of layer set
Contains information about the context of a rendering operation.
static QgsMapLayerRegistry * instance()
Returns the instance pointer, creating the object on the first call.
void useImageToRender(bool theFlag)
Select which Qt class to render with.
bool isInOverview() const
Definition: qgsmapcanvas.h:79
virtual void canvasReleaseEvent(QMouseEvent *e)
Mouse release event for overriding. Default implementation does nothing.
Definition: qgsmaptool.cpp:134
void setLayerSet(const QStringList &layerSet)
updates layer set for overview
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.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
QgsMapRenderer * mapRenderer()
void zoomToFullExtent()
Zoom to the full extent of all layers.
void enableAntiAliasing(bool flag)
bool mRenderFlag
determines whether user has requested to suppress rendering
Definition: qgsmapcanvas.h:463
Class for storing a coordinate reference system (CRS)
A generic message view for displaying QGIS messages.
void zoomScale(double scale)
Zoom to a specific scale.
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:166
double y() const
Definition: qgspoint.h:118
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 useImageToRender(bool flag)
void layerStateChange()
This slot is connected to the visibility change of one or more layers.
QgsRectangle extent() const
Returns the current zoom exent of the map canvas.
QgsMapCanvas(QWidget *parent=0, const char *name=0)
Constructor.
void setMapUnits(QGis::UnitType mapUnits)
Set map units (needed by project properties dialog)
void updateOverview()
void connectNotify(const char *signal)
debugging member invoked when a connect() is made to this object
void crsTransformEnabled(bool)
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.
void setPanningOffset(const QPoint &point)
QPoint rubberStartPoint
Beginning point of a rubber band.
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:199
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
bool readXML(QDomNode &theNode)
read settings
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:483
void updateFullExtent()
Updates the full extent.
static QgsCRSCache * instance()
Definition: qgscrscache.cpp:85
QStringList & layerSet()
returns current layer set
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:209
QgsMapLayer * layer()
Definition: qgsmapcanvas.h:81
void extentsChanged()
Emitted when the extents of the map change.
std::auto_ptr< CanvasProperties > mCanvasProperties
Handle pattern for implementation object.
Definition: qgsmapcanvas.h:411
void mouseMoveEvent(QMouseEvent *e)
Overridden mouse move event.
QgsMapLayer * layer(int index)
return the map layer at position index in the layer stack
void updateMap()
updates pixmap on render progress
void setXMinimum(double x)
Set the minimum x value.
Definition: qgsrectangle.h:159
QgsRectangle layerExtentToOutputExtent(QgsMapLayer *theLayer, QgsRectangle extent)
transform bounding box from layer's CRS to output CRS
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 drawExtentRect()
used for overview canvas to reflect changed extent in main map canvas
void panActionEnd(QPoint releasePoint)
Ends pan action and redraws the canvas.
void mapUnitsChanged()
The map units may have changed, so cope with that.
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 mapToolSet(QgsMapTool *tool)
Emit map tool changed event.
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.