Quantum GIS API Documentation  1.8
src/gui/qgsmapcanvas.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   qgsmapcanvas.cpp  -  description
00003   -------------------
00004 begin                : Sun Jun 30 2002
00005 copyright            : (C) 2002 by Gary E.Sherman
00006 email                : sherman at mrcc.com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 
00019 #include <QtGlobal>
00020 #include <QApplication>
00021 #include <QCursor>
00022 #include <QDir>
00023 #include <QFile>
00024 #include <QGraphicsItem>
00025 #include <QGraphicsScene>
00026 #include <QGraphicsView>
00027 #include <QKeyEvent>
00028 #include <QMouseEvent>
00029 #include <QPainter>
00030 #include <QPaintEvent>
00031 #include <QPixmap>
00032 #include <QRect>
00033 #include <QTextStream>
00034 #include <QResizeEvent>
00035 #include <QString>
00036 #include <QStringList>
00037 #include <QWheelEvent>
00038 
00039 #include "qgis.h"
00040 #include "qgslogger.h"
00041 #include "qgsmapcanvas.h"
00042 #include "qgsmapcanvasmap.h"
00043 #include "qgsmaplayer.h"
00044 #include "qgsmaplayerregistry.h"
00045 #include "qgsmaptoolpan.h"
00046 #include "qgsmaptoolzoom.h"
00047 #include "qgsmaptopixel.h"
00048 #include "qgsmapoverviewcanvas.h"
00049 #include "qgsmaprenderer.h"
00050 #include "qgsmessageviewer.h"
00051 #include "qgsproject.h"
00052 #include "qgsrubberband.h"
00053 #include "qgsvectorlayer.h"
00054 #include <math.h>
00055 
00057 class QgsMapCanvas::CanvasProperties
00058 {
00059   public:
00060 
00061     CanvasProperties() : mouseButtonDown( false ), panSelectorDown( false ) { }
00062 
00064     bool mouseButtonDown;
00065 
00067     QPoint mouseLastXY;
00068 
00070     QPoint rubberStartPoint;
00071 
00073     bool panSelectorDown;
00074 
00075 };
00076 
00077 
00078 
00079 QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
00080     : QGraphicsView( parent )
00081     , mCanvasProperties( new CanvasProperties )
00082     , mNewSize( QSize() )
00083     , mPainting( false )
00084     , mAntiAliasing( false )
00085 {
00086   Q_UNUSED( name );
00087   //disable the update that leads to the resize crash
00088   if ( viewport() )
00089   {
00090 #ifndef ANDROID
00091     viewport()->setAttribute( Qt::WA_PaintOnScreen, true );
00092 #endif //ANDROID
00093   }
00094 
00095   mScene = new QGraphicsScene();
00096   setScene( mScene );
00097   setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00098   setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
00099   mLastExtentIndex = -1;
00100   mCurrentLayer = NULL;
00101   mMapOverview = NULL;
00102   mMapTool = NULL;
00103   mLastNonZoomMapTool = NULL;
00104 
00105   mDrawing = false;
00106   mFrozen = false;
00107   mDirty = true;
00108 
00109   setWheelAction( WheelZoom );
00110 
00111   // by default, the canvas is rendered
00112   mRenderFlag = true;
00113 
00114   setMouseTracking( true );
00115   setFocusPolicy( Qt::StrongFocus );
00116 
00117   mMapRenderer = new QgsMapRenderer;
00118 
00119   // create map canvas item which will show the map
00120   mMap = new QgsMapCanvasMap( this );
00121   mScene->addItem( mMap );
00122   mScene->update(); // porting??
00123 
00124   moveCanvasContents( true );
00125 
00126   connect( mMapRenderer, SIGNAL( drawError( QgsMapLayer* ) ), this, SLOT( showError( QgsMapLayer* ) ) );
00127   connect( mMapRenderer, SIGNAL( hasCrsTransformEnabled( bool ) ), this, SLOT( crsTransformEnabled( bool ) ) );
00128 
00129   crsTransformEnabled( hasCrsTransformEnabled() );
00130 
00131   // project handling
00132   connect( QgsProject::instance(), SIGNAL( readProject( const QDomDocument & ) ),
00133            this, SLOT( readProject( const QDomDocument & ) ) );
00134   connect( QgsProject::instance(), SIGNAL( writeProject( QDomDocument & ) ),
00135            this, SLOT( writeProject( QDomDocument & ) ) );
00136   mMap->resize( size() );
00137 } // QgsMapCanvas ctor
00138 
00139 
00140 QgsMapCanvas::~QgsMapCanvas()
00141 {
00142   if ( mMapTool )
00143   {
00144     mMapTool->deactivate();
00145     mMapTool = NULL;
00146   }
00147   mLastNonZoomMapTool = NULL;
00148 
00149   // delete canvas items prior to deleteing the canvas
00150   // because they might try to update canvas when it's
00151   // already being destructed, ends with segfault
00152   QList<QGraphicsItem*> list = mScene->items();
00153   QList<QGraphicsItem*>::iterator it = list.begin();
00154   while ( it != list.end() )
00155   {
00156     QGraphicsItem* item = *it;
00157     delete item;
00158     it++;
00159   }
00160 
00161   delete mScene;
00162 
00163   delete mMapRenderer;
00164   // mCanvasProperties auto-deleted via std::auto_ptr
00165   // CanvasProperties struct has its own dtor for freeing resources
00166 
00167 } // dtor
00168 
00169 void QgsMapCanvas::enableAntiAliasing( bool theFlag )
00170 {
00171   mAntiAliasing = theFlag;
00172   mMap->enableAntiAliasing( theFlag );
00173   if ( mMapOverview )
00174     mMapOverview->enableAntiAliasing( theFlag );
00175 } // anti aliasing
00176 
00177 void QgsMapCanvas::useImageToRender( bool theFlag )
00178 {
00179   mMap->useImageToRender( theFlag );
00180   refresh(); // redraw the map on change - prevents black map view
00181 }
00182 
00183 QgsMapCanvasMap* QgsMapCanvas::map()
00184 {
00185   return mMap;
00186 }
00187 
00188 QgsMapRenderer* QgsMapCanvas::mapRenderer()
00189 {
00190   return mMapRenderer;
00191 }
00192 
00193 
00194 QgsMapLayer* QgsMapCanvas::layer( int index )
00195 {
00196   QStringList& layers = mMapRenderer->layerSet();
00197   if ( index >= 0 && index < ( int ) layers.size() )
00198     return QgsMapLayerRegistry::instance()->mapLayer( layers[index] );
00199   else
00200     return NULL;
00201 }
00202 
00203 
00204 void QgsMapCanvas::setCurrentLayer( QgsMapLayer* layer )
00205 {
00206   mCurrentLayer = layer;
00207 }
00208 
00209 double QgsMapCanvas::scale()
00210 {
00211   return mMapRenderer->scale();
00212 } // scale
00213 
00214 void QgsMapCanvas::setDirty( bool dirty )
00215 {
00216   mDirty = dirty;
00217 }
00218 
00219 bool QgsMapCanvas::isDirty() const
00220 {
00221   return mDirty;
00222 }
00223 
00224 
00225 
00226 bool QgsMapCanvas::isDrawing()
00227 {
00228   return mDrawing;
00229 } // isDrawing
00230 
00231 
00232 // return the current coordinate transform based on the extents and
00233 // device size
00234 const QgsMapToPixel * QgsMapCanvas::getCoordinateTransform()
00235 {
00236   return mMapRenderer->coordinateTransform();
00237 }
00238 
00239 void QgsMapCanvas::setLayerSet( QList<QgsMapCanvasLayer> &layers )
00240 {
00241   if ( mDrawing )
00242   {
00243     QgsDebugMsg( "NOT updating layer set while drawing" );
00244     return;
00245   }
00246 
00247   // create layer set
00248   QStringList layerSet, layerSetOverview;
00249 
00250   int i;
00251   for ( i = 0; i < layers.size(); i++ )
00252   {
00253     QgsMapCanvasLayer &lyr = layers[i];
00254     if ( !lyr.layer() )
00255     {
00256       continue;
00257     }
00258 
00259     if ( lyr.isVisible() )
00260     {
00261       layerSet.push_back( lyr.layer()->id() );
00262     }
00263 
00264     if ( lyr.isInOverview() )
00265     {
00266       layerSetOverview.push_back( lyr.layer()->id() );
00267     }
00268   }
00269 
00270   QStringList& layerSetOld = mMapRenderer->layerSet();
00271 
00272   bool layerSetChanged = layerSetOld != layerSet;
00273 
00274   // update only if needed
00275   if ( !layerSetChanged )
00276     return;
00277 
00278   QgsDebugMsg( "Layer changed to: " + layerSet.join( ", " ) );
00279 
00280   for ( i = 0; i < layerCount(); i++ )
00281   {
00282     // Add check if vector layer when disconnecting from selectionChanged slot
00283     // Ticket #811 - racicot
00284     QgsMapLayer *currentLayer = layer( i );
00285     disconnect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
00286     disconnect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
00287     QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
00288     if ( isVectLyr )
00289     {
00290       disconnect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
00291     }
00292   }
00293 
00294   mMapRenderer->setLayerSet( layerSet );
00295 
00296   for ( i = 0; i < layerCount(); i++ )
00297   {
00298     // Add check if vector layer when connecting to selectionChanged slot
00299     // Ticket #811 - racicot
00300     QgsMapLayer *currentLayer = layer( i );
00301     connect( currentLayer, SIGNAL( repaintRequested() ), this, SLOT( refresh() ) );
00302     connect( currentLayer, SIGNAL( screenUpdateRequested() ), this, SLOT( updateMap() ) );
00303     QgsVectorLayer *isVectLyr = qobject_cast<QgsVectorLayer *>( currentLayer );
00304     if ( isVectLyr )
00305     {
00306       connect( currentLayer, SIGNAL( selectionChanged() ), this, SLOT( selectionChangedSlot() ) );
00307     }
00308   }
00309 
00310   if ( mMapOverview )
00311   {
00312     mMapOverview->updateFullExtent( fullExtent() );
00313 
00314     QStringList& layerSetOvOld = mMapOverview->layerSet();
00315     if ( layerSetOvOld != layerSetOverview )
00316     {
00317       mMapOverview->setLayerSet( layerSetOverview );
00318     }
00319 
00320     // refresh overview maplayers even if layer set is the same
00321     // because full extent might have changed
00322     updateOverview();
00323   }
00324 
00325   QgsDebugMsg( "Layers have changed, refreshing" );
00326   emit layersChanged();
00327 
00328   refresh();
00329 
00330 } // setLayerSet
00331 
00332 void QgsMapCanvas::enableOverviewMode( QgsMapOverviewCanvas* overview )
00333 {
00334   if ( mMapOverview )
00335   {
00336     // disconnect old map overview if exists
00337     disconnect( mMapRenderer, SIGNAL( hasCrsTransformEnabled( bool ) ),
00338                 mMapOverview, SLOT( hasCrsTransformEnabled( bool ) ) );
00339     disconnect( mMapRenderer, SIGNAL( destinationSrsChanged() ),
00340                 mMapOverview, SLOT( destinationSrsChanged() ) );
00341 
00342     // map overview is not owned by map canvas so don't delete it...
00343   }
00344 
00345   mMapOverview = overview;
00346 
00347   if ( overview )
00348   {
00349     // connect to the map render to copy its projection settings
00350     connect( mMapRenderer, SIGNAL( hasCrsTransformEnabled( bool ) ),
00351              overview,     SLOT( hasCrsTransformEnabled( bool ) ) );
00352     connect( mMapRenderer, SIGNAL( destinationSrsChanged() ),
00353              overview,     SLOT( destinationSrsChanged() ) );
00354   }
00355 }
00356 
00357 
00358 void QgsMapCanvas::updateOverview()
00359 {
00360   // redraw overview
00361   if ( mMapOverview )
00362   {
00363     mMapOverview->refresh();
00364   }
00365 }
00366 
00367 
00368 QgsMapLayer* QgsMapCanvas::currentLayer()
00369 {
00370   return mCurrentLayer;
00371 }
00372 
00373 
00374 void QgsMapCanvas::refresh()
00375 {
00376   // we can't draw again if already drawing...
00377   if ( mDrawing )
00378     return;
00379 
00380   mDrawing = true;
00381 
00382   if ( mRenderFlag && !mFrozen )
00383   {
00384     clear();
00385 
00386     // Tell the user we're going to be a while
00387     QApplication::setOverrideCursor( Qt::WaitCursor );
00388 
00389     emit renderStarting();
00390 
00391     mMap->render();
00392 
00393     mDirty = false;
00394 
00395     // notify any listeners that rendering is complete
00396     QPainter p;
00397     p.begin( &mMap->paintDevice() );
00398     emit renderComplete( &p );
00399     p.end();
00400 
00401     // notifies current map tool
00402     if ( mMapTool )
00403       mMapTool->renderComplete();
00404 
00405     // Tell the user we've finished going to be a while
00406     QApplication::restoreOverrideCursor();
00407   }
00408 
00409   mDrawing = false;
00410 } // refresh
00411 
00412 void QgsMapCanvas::updateMap()
00413 {
00414   if ( mMap )
00415   {
00416     mMap->updateContents();
00417   }
00418 }
00419 
00420 //the format defaults to "PNG" if not specified
00421 void QgsMapCanvas::saveAsImage( QString theFileName, QPixmap * theQPixmap, QString theFormat )
00422 {
00423   //
00424   //check if the optional QPaintDevice was supplied
00425   //
00426   if ( theQPixmap != NULL )
00427   {
00428     // render
00429     QPainter painter;
00430     painter.begin( theQPixmap );
00431     mMapRenderer->render( &painter );
00432     emit renderComplete( &painter );
00433     painter.end();
00434 
00435     theQPixmap->save( theFileName, theFormat.toLocal8Bit().data() );
00436   }
00437   else //use the map view
00438   {
00439     QPixmap *pixmap = dynamic_cast<QPixmap *>( &mMap->paintDevice() );
00440     if ( !pixmap )
00441       return;
00442 
00443     pixmap->save( theFileName, theFormat.toLocal8Bit().data() );
00444   }
00445   //create a world file to go with the image...
00446   QgsRectangle myRect = mMapRenderer->extent();
00447   QString myHeader;
00448   // note: use 17 places of precision for all numbers output
00449   //Pixel XDim
00450   myHeader += QString::number( mapUnitsPerPixel(), 'g', 17 ) + "\r\n";
00451   //Rotation on y axis - hard coded
00452   myHeader += "0 \r\n";
00453   //Rotation on x axis - hard coded
00454   myHeader += "0 \r\n";
00455   //Pixel YDim - almost always negative - see
00456   //http://en.wikipedia.org/wiki/World_file#cite_note-2
00457   myHeader += "-" + QString::number( mapUnitsPerPixel(), 'g', 17 ) + "\r\n";
00458   //Origin X (center of top left cell)
00459   myHeader += QString::number( myRect.xMinimum() + ( mapUnitsPerPixel() / 2 ), 'g', 17 ) + "\r\n";
00460   //Origin Y (center of top left cell)
00461   myHeader += QString::number( myRect.yMaximum() - ( mapUnitsPerPixel() / 2 ), 'g', 17 ) + "\r\n";
00462   QFileInfo myInfo  = QFileInfo( theFileName );
00463   // allow dotted names
00464   QString myWorldFileName = myInfo.absolutePath() + "/" + myInfo.completeBaseName() + "." + theFormat + "w";
00465   QFile myWorldFile( myWorldFileName );
00466   if ( !myWorldFile.open( QIODevice::WriteOnly ) ) //don't use QIODevice::Text
00467   {
00468     return;
00469   }
00470   QTextStream myStream( &myWorldFile );
00471   myStream << myHeader;
00472 } // saveAsImage
00473 
00474 
00475 
00476 QgsRectangle QgsMapCanvas::extent() const
00477 {
00478   return mMapRenderer->extent();
00479 } // extent
00480 
00481 QgsRectangle QgsMapCanvas::fullExtent() const
00482 {
00483   return mMapRenderer->fullExtent();
00484 } // extent
00485 
00486 void QgsMapCanvas::updateFullExtent()
00487 {
00488   // projection settings have changed
00489 
00490   QgsDebugMsg( "updating full extent" );
00491 
00492   mMapRenderer->updateFullExtent();
00493   if ( mMapOverview )
00494   {
00495     mMapOverview->updateFullExtent( fullExtent() );
00496     updateOverview();
00497   }
00498   refresh();
00499 }
00500 
00501 void QgsMapCanvas::setExtent( QgsRectangle const & r )
00502 {
00503   if ( mDrawing )
00504   {
00505     return;
00506   }
00507 
00508   QgsRectangle current = extent();
00509 
00510   if ( r.isEmpty() )
00511   {
00512     QgsDebugMsg( "Empty extent - keeping old extent with new center!" );
00513     QgsRectangle e( QgsPoint( r.center().x() - current.width() / 2.0, r.center().y() - current.height() / 2.0 ),
00514                     QgsPoint( r.center().x() + current.width() / 2.0, r.center().y() + current.height() / 2.0 ) );
00515     mMapRenderer->setExtent( e );
00516   }
00517   else
00518   {
00519     mMapRenderer->setExtent( r );
00520   }
00521   emit extentsChanged();
00522   updateScale();
00523   if ( mMapOverview )
00524     mMapOverview->drawExtentRect();
00525   if ( mLastExtent.size() > 20 )
00526     mLastExtent.removeAt( 0 );
00527 
00528   //clear all extent items after current index
00529   for ( int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
00530   {
00531     mLastExtent.removeAt( i );
00532   }
00533 
00534   mLastExtent.append( extent() ) ;
00535 
00536   // adjust history to no more than 20
00537   if ( mLastExtent.size() > 20 )
00538   {
00539     mLastExtent.removeAt( 0 );
00540   }
00541 
00542   // the last item is the current extent
00543   mLastExtentIndex = mLastExtent.size() - 1;
00544 
00545   // update controls' enabled state
00546   emit zoomLastStatusChanged( mLastExtentIndex > 0 );
00547   emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
00548   // notify canvas items of change
00549   updateCanvasItemPositions();
00550 
00551 } // setExtent
00552 
00553 
00554 void QgsMapCanvas::updateScale()
00555 {
00556   double scale = mMapRenderer->scale();
00557 
00558   emit scaleChanged( scale );
00559 }
00560 
00561 
00562 void QgsMapCanvas::clear()
00563 {
00564   // Indicate to the next paint event that we need to rebuild the canvas contents
00565   setDirty( true );
00566 
00567 } // clear
00568 
00569 
00570 
00571 void QgsMapCanvas::zoomToFullExtent()
00572 {
00573   if ( mDrawing )
00574   {
00575     return;
00576   }
00577 
00578   QgsRectangle extent = fullExtent();
00579   // If the full extent is an empty set, don't do the zoom
00580   if ( !extent.isEmpty() )
00581   {
00582     // Add a 5% margin around the full extent
00583     extent.scale( 1.05 );
00584     setExtent( extent );
00585   }
00586   refresh();
00587 
00588 } // zoomToFullExtent
00589 
00590 
00591 
00592 void QgsMapCanvas::zoomToPreviousExtent()
00593 {
00594   if ( mDrawing )
00595   {
00596     return;
00597   }
00598 
00599   if ( mLastExtentIndex > 0 )
00600   {
00601     mLastExtentIndex--;
00602     mMapRenderer->setExtent( mLastExtent[mLastExtentIndex] );
00603     emit extentsChanged();
00604     updateScale();
00605     if ( mMapOverview )
00606       mMapOverview->drawExtentRect();
00607     refresh();
00608     // update controls' enabled state
00609     emit zoomLastStatusChanged( mLastExtentIndex > 0 );
00610     emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
00611     // notify canvas items of change
00612     updateCanvasItemPositions();
00613   }
00614 
00615 } // zoomToPreviousExtent
00616 
00617 void QgsMapCanvas::zoomToNextExtent()
00618 {
00619   if ( mDrawing )
00620   {
00621     return;
00622   }
00623   if ( mLastExtentIndex < mLastExtent.size() - 1 )
00624   {
00625     mLastExtentIndex++;
00626     mMapRenderer->setExtent( mLastExtent[mLastExtentIndex] );
00627     emit extentsChanged();
00628     updateScale();
00629     if ( mMapOverview )
00630       mMapOverview->drawExtentRect();
00631     refresh();
00632     // update controls' enabled state
00633     emit zoomLastStatusChanged( mLastExtentIndex > 0 );
00634     emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
00635     // notify canvas items of change
00636     updateCanvasItemPositions();
00637   }
00638 }// zoomToNextExtent
00639 
00640 void QgsMapCanvas::clearExtentHistory()
00641 {
00642   mLastExtent.clear(); // clear the zoom history list
00643   mLastExtent.append( extent() ) ; // set the current extent in the list
00644   mLastExtentIndex = mLastExtent.size() - 1;
00645   // update controls' enabled state
00646   emit zoomLastStatusChanged( mLastExtentIndex > 0 );
00647   emit zoomNextStatusChanged( mLastExtentIndex < mLastExtent.size() - 1 );
00648 }// clearExtentHistory
00649 
00650 
00651 bool QgsMapCanvas::hasCrsTransformEnabled()
00652 {
00653   return mMapRenderer->hasCrsTransformEnabled();
00654 }
00655 
00656 void QgsMapCanvas::mapUnitsChanged()
00657 {
00658   // We assume that if the map units have changed, the changed value
00659   // will be accessible from QgsMapRenderer
00660 
00661   // And then force a redraw of the scale number in the status bar
00662   updateScale();
00663 
00664   // And then redraw the map to force the scale bar to update
00665   // itself. This is less than ideal as the entire map gets redrawn
00666   // just to get the scale bar to redraw itself. If we ask the scale
00667   // bar to redraw itself without redrawing the map, the existing
00668   // scale bar is not removed, and we end up with two scale bars in
00669   // the same location. This can perhaps be fixed when/if the scale
00670   // bar is done as a transparent layer on top of the map canvas.
00671   refresh();
00672 }
00673 
00674 void QgsMapCanvas::zoomToSelected( QgsVectorLayer* layer )
00675 {
00676   if ( mDrawing )
00677   {
00678     return;
00679   }
00680 
00681   if ( layer == NULL )
00682   {
00683     // use current layer by default
00684     layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
00685   }
00686 
00687   if ( layer == NULL )
00688   {
00689     return;
00690   }
00691 
00692   if ( layer->selectedFeatureCount() == 0 )
00693   {
00694     return;
00695   }
00696 
00697   QgsRectangle rect = mMapRenderer->layerExtentToOutputExtent( layer, layer->boundingBoxOfSelected() );
00698 
00699   // no selected features, only one selected point feature
00700   //or two point features with the same x- or y-coordinates
00701   if ( rect.isEmpty() )
00702   {
00703     // zoom in
00704     QgsPoint c = rect.center();
00705     rect = extent();
00706     rect.expand( 0.25, &c );
00707   }
00708   //zoom to an area
00709   else
00710   {
00711     // Expand rect to give a bit of space around the selected
00712     // objects so as to keep them clear of the map boundaries
00713     // The same 5% should apply to all margins.
00714     rect.scale( 1.05 );
00715   }
00716 
00717   setExtent( rect );
00718   refresh();
00719 } // zoomToSelected
00720 
00721 void QgsMapCanvas::panToSelected( QgsVectorLayer* layer )
00722 {
00723   if ( mDrawing )
00724   {
00725     return;
00726   }
00727 
00728   if ( layer == NULL )
00729   {
00730     // use current layer by default
00731     layer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
00732   }
00733 
00734   if ( layer == NULL )
00735   {
00736     return;
00737   }
00738 
00739   if ( layer->selectedFeatureCount() == 0 )
00740   {
00741     return;
00742   }
00743 
00744   QgsRectangle rect = mMapRenderer->layerExtentToOutputExtent( layer, layer->boundingBoxOfSelected() );
00745   setExtent( QgsRectangle( rect.center(), rect.center() ) );
00746   refresh();
00747 } // panToSelected
00748 
00749 void QgsMapCanvas::keyPressEvent( QKeyEvent * e )
00750 {
00751 
00752   if ( mDrawing )
00753   {
00754     e->ignore();
00755   }
00756 
00757   emit keyPressed( e );
00758 
00759   if ( mCanvasProperties->mouseButtonDown || mCanvasProperties->panSelectorDown )
00760     return;
00761 
00762   QPainter paint;
00763   QPen     pen( Qt::gray );
00764   QgsPoint ll, ur;
00765 
00766   if ( ! mCanvasProperties->mouseButtonDown )
00767   {
00768     // Don't want to interfer with mouse events
00769 
00770     QgsRectangle currentExtent = mMapRenderer->extent();
00771     double dx = qAbs(( currentExtent.xMaximum() - currentExtent.xMinimum() ) / 4 );
00772     double dy = qAbs(( currentExtent.yMaximum() - currentExtent.yMinimum() ) / 4 );
00773 
00774     switch ( e->key() )
00775     {
00776       case Qt::Key_Left:
00777         QgsDebugMsg( "Pan left" );
00778 
00779         currentExtent.setXMinimum( currentExtent.xMinimum() - dx );
00780         currentExtent.setXMaximum( currentExtent.xMaximum() - dx );
00781         setExtent( currentExtent );
00782         refresh();
00783         break;
00784 
00785       case Qt::Key_Right:
00786         QgsDebugMsg( "Pan right" );
00787 
00788         currentExtent.setXMinimum( currentExtent.xMinimum() + dx );
00789         currentExtent.setXMaximum( currentExtent.xMaximum() + dx );
00790         setExtent( currentExtent );
00791         refresh();
00792         break;
00793 
00794       case Qt::Key_Up:
00795         QgsDebugMsg( "Pan up" );
00796 
00797         currentExtent.setYMaximum( currentExtent.yMaximum() + dy );
00798         currentExtent.setYMinimum( currentExtent.yMinimum() + dy );
00799         setExtent( currentExtent );
00800         refresh();
00801         break;
00802 
00803       case Qt::Key_Down:
00804         QgsDebugMsg( "Pan down" );
00805 
00806         currentExtent.setYMaximum( currentExtent.yMaximum() - dy );
00807         currentExtent.setYMinimum( currentExtent.yMinimum() - dy );
00808         setExtent( currentExtent );
00809         refresh();
00810         break;
00811 
00812 
00813 
00814       case Qt::Key_Space:
00815         QgsDebugMsg( "Pressing pan selector" );
00816 
00817         //mCanvasProperties->dragging = true;
00818         if ( ! e->isAutoRepeat() )
00819         {
00820           mCanvasProperties->panSelectorDown = true;
00821           mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
00822         }
00823         break;
00824 
00825       case Qt::Key_PageUp:
00826         QgsDebugMsg( "Zoom in" );
00827         zoomIn();
00828         break;
00829 
00830       case Qt::Key_PageDown:
00831         QgsDebugMsg( "Zoom out" );
00832         zoomOut();
00833         break;
00834 
00835       default:
00836         // Pass it on
00837         if ( mMapTool )
00838         {
00839           mMapTool->keyPressEvent( e );
00840         }
00841         e->ignore();
00842 
00843         QgsDebugMsg( "Ignoring key: " + QString::number( e->key() ) );
00844 
00845     }
00846   }
00847 } //keyPressEvent()
00848 
00849 void QgsMapCanvas::keyReleaseEvent( QKeyEvent * e )
00850 {
00851   QgsDebugMsg( "keyRelease event" );
00852 
00853   if ( mDrawing )
00854   {
00855     return;
00856   }
00857 
00858   switch ( e->key() )
00859   {
00860     case Qt::Key_Space:
00861       if ( !e->isAutoRepeat() && mCanvasProperties->panSelectorDown )
00862       {
00863         QgsDebugMsg( "Releasing pan selector" );
00864 
00865         mCanvasProperties->panSelectorDown = false;
00866         panActionEnd( mCanvasProperties->mouseLastXY );
00867       }
00868       break;
00869 
00870     default:
00871       // Pass it on
00872       if ( mMapTool )
00873       {
00874         mMapTool->keyReleaseEvent( e );
00875       }
00876 
00877       e->ignore();
00878 
00879       QgsDebugMsg( "Ignoring key release: " + QString::number( e->key() ) );
00880   }
00881 
00882   emit keyReleased( e );
00883 
00884 } //keyReleaseEvent()
00885 
00886 
00887 void QgsMapCanvas::mouseDoubleClickEvent( QMouseEvent * e )
00888 {
00889   if ( mDrawing )
00890   {
00891     return;
00892   }
00893 
00894   // call handler of current map tool
00895   if ( mMapTool )
00896     mMapTool->canvasDoubleClickEvent( e );
00897 } // mouseDoubleClickEvent
00898 
00899 
00900 void QgsMapCanvas::mousePressEvent( QMouseEvent * e )
00901 {
00902   if ( mDrawing )
00903   {
00904     return;
00905   }
00906 
00907   //use middle mouse button for panning, map tools won't receive any events in that case
00908   if ( e->button() == Qt::MidButton )
00909   {
00910     mCanvasProperties->panSelectorDown = true;
00911     mCanvasProperties->rubberStartPoint = mCanvasProperties->mouseLastXY;
00912   }
00913   else
00914   {
00915 
00916     // call handler of current map tool
00917     if ( mMapTool )
00918       mMapTool->canvasPressEvent( e );
00919   }
00920 
00921   if ( mCanvasProperties->panSelectorDown )
00922   {
00923     return;
00924   }
00925 
00926   mCanvasProperties->mouseButtonDown = true;
00927   mCanvasProperties->rubberStartPoint = e->pos();
00928 
00929 } // mousePressEvent
00930 
00931 
00932 void QgsMapCanvas::mouseReleaseEvent( QMouseEvent * e )
00933 {
00934   if ( mDrawing )
00935   {
00936     return;
00937   }
00938 
00939   //use middle mouse button for panning, map tools won't receive any events in that case
00940   if ( e->button() == Qt::MidButton )
00941   {
00942     mCanvasProperties->panSelectorDown = false;
00943     panActionEnd( mCanvasProperties->mouseLastXY );
00944   }
00945   else
00946   {
00947     // call handler of current map tool
00948     if ( mMapTool )
00949     {
00950       // right button was pressed in zoom tool? return to previous non zoom tool
00951       if ( e->button() == Qt::RightButton && mMapTool->isTransient() )
00952       {
00953         QgsDebugMsg( "Right click in map tool zoom or pan, last tool is " +
00954                      QString( mLastNonZoomMapTool ? "not null." : "null." ) );
00955 
00956         QgsVectorLayer *vlayer = qobject_cast<QgsVectorLayer *>( mCurrentLayer );
00957 
00958         // change to older non-zoom tool
00959         if ( mLastNonZoomMapTool
00960              && ( !mLastNonZoomMapTool->isEditTool() || ( vlayer && vlayer->isEditable() ) ) )
00961         {
00962           QgsMapTool* t = mLastNonZoomMapTool;
00963           mLastNonZoomMapTool = NULL;
00964           setMapTool( t );
00965         }
00966         return;
00967       }
00968       mMapTool->canvasReleaseEvent( e );
00969     }
00970   }
00971 
00972 
00973   mCanvasProperties->mouseButtonDown = false;
00974 
00975   if ( mCanvasProperties->panSelectorDown )
00976     return;
00977 
00978 } // mouseReleaseEvent
00979 
00980 void QgsMapCanvas::resizeEvent( QResizeEvent * e )
00981 {
00982   mNewSize = e->size();
00983 }
00984 
00985 void QgsMapCanvas::paintEvent( QPaintEvent *e )
00986 {
00987   if ( mNewSize.isValid() )
00988   {
00989     if ( mPainting || mDrawing )
00990     {
00991       //cancel current render progress
00992       if ( mMapRenderer )
00993       {
00994         QgsRenderContext* theRenderContext = mMapRenderer->rendererContext();
00995         if ( theRenderContext )
00996         {
00997           theRenderContext->setRenderingStopped( true );
00998         }
00999       }
01000       return;
01001     }
01002 
01003     mPainting = true;
01004 
01005     while ( mNewSize.isValid() )
01006     {
01007       QSize lastSize = mNewSize;
01008       mNewSize = QSize();
01009 
01010       //set map size before scene size helps keep scene indexes updated properly
01011       // this was the cause of rubberband artifacts
01012       mMap->resize( lastSize );
01013       mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
01014 
01015       // notify canvas items of change
01016       updateCanvasItemPositions();
01017 
01018       updateScale();
01019 
01020       refresh();
01021 
01022       emit extentsChanged();
01023     }
01024 
01025     mPainting = false;
01026   }
01027 
01028   QGraphicsView::paintEvent( e );
01029 } // paintEvent
01030 
01031 void QgsMapCanvas::updateCanvasItemPositions()
01032 {
01033   QList<QGraphicsItem*> list = mScene->items();
01034   QList<QGraphicsItem*>::iterator it = list.begin();
01035   while ( it != list.end() )
01036   {
01037     QgsMapCanvasItem* item = dynamic_cast<QgsMapCanvasItem *>( *it );
01038 
01039     if ( item )
01040     {
01041       item->updatePosition();
01042     }
01043 
01044     it++;
01045   }
01046 }
01047 
01048 
01049 void QgsMapCanvas::wheelEvent( QWheelEvent *e )
01050 {
01051   // Zoom the map canvas in response to a mouse wheel event. Moving the
01052   // wheel forward (away) from the user zooms in
01053 
01054   QgsDebugMsg( "Wheel event delta " + QString::number( e->delta() ) );
01055 
01056   if ( mDrawing )
01057   {
01058     return;
01059   }
01060 
01061   switch ( mWheelAction )
01062   {
01063     case WheelZoom:
01064       // zoom without changing extent
01065       if ( e->delta() > 0 )
01066         zoomIn();
01067       else
01068         zoomOut();
01069       break;
01070 
01071     case WheelZoomAndRecenter:
01072       // zoom and don't change extent
01073       zoomWithCenter( e->x(), e->y(), e->delta() > 0 );
01074       break;
01075 
01076     case WheelZoomToMouseCursor:
01077     {
01078       // zoom map to mouse cursor
01079       double scaleFactor = e->delta() > 0 ? 1 / mWheelZoomFactor : mWheelZoomFactor;
01080 
01081       QgsPoint oldCenter( mMapRenderer->extent().center() );
01082       QgsPoint mousePos( getCoordinateTransform()->toMapPoint( e->x(), e->y() ) );
01083       QgsPoint newCenter( mousePos.x() + (( oldCenter.x() - mousePos.x() ) * scaleFactor ),
01084                           mousePos.y() + (( oldCenter.y() - mousePos.y() ) * scaleFactor ) );
01085 
01086       // same as zoomWithCenter (no coordinate transformations are needed)
01087       QgsRectangle extent = mMapRenderer->extent();
01088       extent.scale( scaleFactor, &newCenter );
01089       setExtent( extent );
01090       refresh();
01091       break;
01092     }
01093 
01094     case WheelNothing:
01095       // well, nothing!
01096       break;
01097   }
01098 }
01099 
01100 void QgsMapCanvas::setWheelAction( WheelAction action, double factor )
01101 {
01102   mWheelAction = action;
01103   mWheelZoomFactor = factor;
01104 }
01105 
01106 void QgsMapCanvas::zoomIn()
01107 {
01108   zoomByFactor( 1 / mWheelZoomFactor );
01109 }
01110 
01111 void QgsMapCanvas::zoomOut()
01112 {
01113   zoomByFactor( mWheelZoomFactor );
01114 }
01115 
01116 void QgsMapCanvas::zoomScale( double newScale )
01117 {
01118   zoomByFactor( newScale / scale() );
01119 }
01120 
01121 void QgsMapCanvas::zoomWithCenter( int x, int y, bool zoomIn )
01122 {
01123   if ( mDrawing )
01124   {
01125     return;
01126   }
01127 
01128   double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
01129 
01130   // transform the mouse pos to map coordinates
01131   QgsPoint center  = getCoordinateTransform()->toMapPoint( x, y );
01132   QgsRectangle r = mMapRenderer->extent();
01133   r.scale( scaleFactor, &center );
01134   setExtent( r );
01135   refresh();
01136 }
01137 
01138 void QgsMapCanvas::mouseMoveEvent( QMouseEvent * e )
01139 {
01140   if ( mDrawing )
01141   {
01142     return;
01143   }
01144 
01145   mCanvasProperties->mouseLastXY = e->pos();
01146 
01147   if ( mCanvasProperties->panSelectorDown )
01148   {
01149     panAction( e );
01150   }
01151   else
01152   {
01153     // call handler of current map tool
01154     if ( mMapTool )
01155       mMapTool->canvasMoveEvent( e );
01156   }
01157 
01158   // show x y on status bar
01159   QPoint xy = e->pos();
01160   QgsPoint coord = getCoordinateTransform()->toMapCoordinates( xy );
01161   emit xyCoordinates( coord );
01162 } // mouseMoveEvent
01163 
01164 
01165 
01167 void QgsMapCanvas::setMapTool( QgsMapTool* tool )
01168 {
01169   if ( !tool )
01170     return;
01171 
01172   if ( mMapTool )
01173   {
01174     disconnect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
01175     mMapTool->deactivate();
01176   }
01177 
01178   if ( tool->isTransient() && mMapTool && !mMapTool->isTransient() )
01179   {
01180     // if zoom or pan tool will be active, save old tool
01181     // to bring it back on right click
01182     // (but only if it wasn't also zoom or pan tool)
01183     mLastNonZoomMapTool = mMapTool;
01184   }
01185   else
01186   {
01187     mLastNonZoomMapTool = NULL;
01188   }
01189 
01190   // set new map tool and activate it
01191   mMapTool = tool;
01192   if ( mMapTool )
01193   {
01194     connect( mMapTool, SIGNAL( destroyed() ), this, SLOT( mapToolDestroyed() ) );
01195     mMapTool->activate();
01196   }
01197 
01198   emit mapToolSet( mMapTool );
01199 } // setMapTool
01200 
01201 void QgsMapCanvas::unsetMapTool( QgsMapTool* tool )
01202 {
01203   if ( mMapTool && mMapTool == tool )
01204   {
01205     mMapTool->deactivate();
01206     mMapTool = NULL;
01207     emit mapToolSet( NULL );
01208     setCursor( Qt::ArrowCursor );
01209   }
01210 
01211   if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
01212   {
01213     mLastNonZoomMapTool = NULL;
01214   }
01215 }
01216 
01218 void QgsMapCanvas::setCanvasColor( const QColor & theColor )
01219 {
01220   // background of map's pixmap
01221   mMap->setBackgroundColor( theColor );
01222 
01223   // background of the QGraphicsView
01224   QBrush bgBrush( theColor );
01225   setBackgroundBrush( bgBrush );
01226 #if 0
01227   QPalette palette;
01228   palette.setColor( backgroundRole(), theColor );
01229   setPalette( palette );
01230 #endif
01231 
01232   // background of QGraphicsScene
01233   mScene->setBackgroundBrush( bgBrush );
01234 } // setBackgroundColor
01235 
01236 QColor QgsMapCanvas::canvasColor() const
01237 {
01238   return mScene->backgroundBrush().color();
01239 }
01240 
01241 int QgsMapCanvas::layerCount() const
01242 {
01243   return mMapRenderer->layerSet().size();
01244 } // layerCount
01245 
01246 
01247 QList<QgsMapLayer*> QgsMapCanvas::layers() const
01248 {
01249   QList<QgsMapLayer*> lst;
01250   foreach( QString layerID, mMapRenderer->layerSet() )
01251   {
01252     QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( layerID );
01253     if ( layer )
01254       lst.append( layer );
01255   }
01256   return lst;
01257 }
01258 
01259 
01260 void QgsMapCanvas::layerStateChange()
01261 {
01262   // called when a layer has changed visibility setting
01263 
01264   refresh();
01265 
01266 } // layerStateChange
01267 
01268 
01269 
01270 void QgsMapCanvas::freeze( bool frz )
01271 {
01272   mFrozen = frz;
01273 } // freeze
01274 
01275 bool QgsMapCanvas::isFrozen()
01276 {
01277   return mFrozen;
01278 } // freeze
01279 
01280 
01281 QPixmap& QgsMapCanvas::canvasPixmap()
01282 {
01283   QPixmap *pixmap = dynamic_cast<QPixmap *>( &canvasPaintDevice() );
01284   if ( pixmap )
01285   {
01286     return *pixmap;
01287   }
01288 
01289   qWarning( "QgsMapCanvas::canvasPixmap() deprecated - returning static pixmap instance - use QgsMapCanvas::paintDevice()" );
01290 
01291   static QPixmap staticPixmap;
01292 
01293   QImage *image = dynamic_cast<QImage *>( &mMap->paintDevice() );
01294   if ( image )
01295   {
01296     staticPixmap = QPixmap::fromImage( *image );
01297   }
01298   else
01299   {
01300     staticPixmap = QPixmap( canvasPaintDevice().width(), canvasPaintDevice().height() );
01301   }
01302 
01303   return staticPixmap;
01304 } // canvasPixmap
01305 
01306 QPaintDevice &QgsMapCanvas::canvasPaintDevice()
01307 {
01308   return mMap->paintDevice();
01309 }
01310 
01311 double QgsMapCanvas::mapUnitsPerPixel() const
01312 {
01313   return mMapRenderer->mapUnitsPerPixel();
01314 } // mapUnitsPerPixel
01315 
01316 
01317 void QgsMapCanvas::setMapUnits( QGis::UnitType u )
01318 {
01319   QgsDebugMsg( "Setting map units to " + QString::number( static_cast<int>( u ) ) );
01320   mMapRenderer->setMapUnits( u );
01321 }
01322 
01323 
01324 QGis::UnitType QgsMapCanvas::mapUnits() const
01325 {
01326   return mMapRenderer->mapUnits();
01327 }
01328 
01329 
01330 void QgsMapCanvas::setRenderFlag( bool theFlag )
01331 {
01332   mRenderFlag = theFlag;
01333   if ( mMapRenderer )
01334   {
01335     QgsRenderContext* rc = mMapRenderer->rendererContext();
01336     if ( rc )
01337     {
01338       rc->setRenderingStopped( !theFlag );
01339     }
01340   }
01341 
01342   if ( mRenderFlag )
01343   {
01344     refresh();
01345   }
01346 }
01347 
01348 void QgsMapCanvas::connectNotify( const char * signal )
01349 {
01350   Q_UNUSED( signal );
01351   QgsDebugMsg( "QgsMapCanvas connected to " + QString( signal ) );
01352 } //connectNotify
01353 
01354 
01355 
01356 QgsMapTool* QgsMapCanvas::mapTool()
01357 {
01358   return mMapTool;
01359 }
01360 
01361 void QgsMapCanvas::panActionEnd( QPoint releasePoint )
01362 {
01363   if ( mDrawing )
01364   {
01365     return;
01366   }
01367 
01368   // move map image and other items to standard position
01369   moveCanvasContents( true ); // true means reset
01370 
01371   // use start and end box points to calculate the extent
01372   QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
01373   QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );
01374 
01375   double dx = qAbs( end.x() - start.x() );
01376   double dy = qAbs( end.y() - start.y() );
01377 
01378   // modify the extent
01379   QgsRectangle r = mMapRenderer->extent();
01380 
01381   if ( end.x() < start.x() )
01382   {
01383     r.setXMinimum( r.xMinimum() + dx );
01384     r.setXMaximum( r.xMaximum() + dx );
01385   }
01386   else
01387   {
01388     r.setXMinimum( r.xMinimum() - dx );
01389     r.setXMaximum( r.xMaximum() - dx );
01390   }
01391 
01392   if ( end.y() < start.y() )
01393   {
01394     r.setYMaximum( r.yMaximum() + dy );
01395     r.setYMinimum( r.yMinimum() + dy );
01396 
01397   }
01398   else
01399   {
01400     r.setYMaximum( r.yMaximum() - dy );
01401     r.setYMinimum( r.yMinimum() - dy );
01402 
01403   }
01404 
01405   setExtent( r );
01406   refresh();
01407 }
01408 
01409 void QgsMapCanvas::panAction( QMouseEvent * e )
01410 {
01411   Q_UNUSED( e );
01412 
01413   if ( mDrawing )
01414   {
01415     return;
01416   }
01417 
01418   // move all map canvas items
01419   moveCanvasContents();
01420 
01421   // update canvas
01422   //updateContents(); // TODO: need to update?
01423 }
01424 
01425 void QgsMapCanvas::moveCanvasContents( bool reset )
01426 {
01427   if ( mDrawing )
01428   {
01429     return;
01430   }
01431 
01432   QPoint pnt( 0, 0 );
01433   if ( !reset )
01434     pnt += mCanvasProperties->mouseLastXY - mCanvasProperties->rubberStartPoint;
01435 
01436   mMap->setPanningOffset( pnt );
01437 
01438   QList<QGraphicsItem*> list = mScene->items();
01439   QList<QGraphicsItem*>::iterator it = list.begin();
01440   while ( it != list.end() )
01441   {
01442     QGraphicsItem* item = *it;
01443 
01444     if ( item != mMap )
01445     {
01446       // this tells map canvas item to draw with offset
01447       QgsMapCanvasItem* canvasItem = dynamic_cast<QgsMapCanvasItem *>( item );
01448       if ( canvasItem )
01449         canvasItem->setPanningOffset( pnt );
01450     }
01451 
01452     it++;
01453   }
01454 
01455   // show items
01456   updateCanvasItemPositions();
01457 
01458 }
01459 
01460 void QgsMapCanvas::showError( QgsMapLayer * mapLayer )
01461 {
01462 #if 0
01463   QMessageBox::warning(
01464     this,
01465     mapLayer->lastErrorTitle(),
01466     tr( "Could not draw %1 because:\n%2", "COMMENTED OUT" ).arg( mapLayer->name() ).arg( mapLayer->lastError() )
01467   );
01468 #endif
01469 
01470   QgsMessageViewer * mv = new QgsMessageViewer( this );
01471   mv->setWindowTitle( mapLayer->lastErrorTitle() );
01472   mv->setMessageAsPlainText( tr( "Could not draw %1 because:\n%2" )
01473                              .arg( mapLayer->name() ).arg( mapLayer->lastError() ) );
01474   mv->exec();
01475   //MH
01476   //QgsMessageViewer automatically sets delete on close flag
01477   //so deleting mv would lead to a segfault
01478 }
01479 
01480 QPoint QgsMapCanvas::mouseLastXY()
01481 {
01482   return mCanvasProperties->mouseLastXY;
01483 }
01484 
01485 void QgsMapCanvas::readProject( const QDomDocument & doc )
01486 {
01487   QDomNodeList nodes = doc.elementsByTagName( "mapcanvas" );
01488   if ( nodes.count() )
01489   {
01490     QDomNode node = nodes.item( 0 );
01491     mMapRenderer->readXML( node );
01492     clearExtentHistory(); // clear the extent history on project load
01493   }
01494   else
01495   {
01496     QgsDebugMsg( "Couldn't read mapcanvas information from project" );
01497   }
01498 }
01499 
01500 void QgsMapCanvas::writeProject( QDomDocument & doc )
01501 {
01502   // create node "mapcanvas" and call mMapRenderer->writeXML()
01503 
01504   QDomNodeList nl = doc.elementsByTagName( "qgis" );
01505   if ( !nl.count() )
01506   {
01507     QgsDebugMsg( "Unable to find qgis element in project file" );
01508     return;
01509   }
01510   QDomNode qgisNode = nl.item( 0 );  // there should only be one, so zeroth element ok
01511 
01512   QDomElement mapcanvasNode = doc.createElement( "mapcanvas" );
01513   qgisNode.appendChild( mapcanvasNode );
01514   mMapRenderer->writeXML( mapcanvasNode, doc );
01515 }
01516 
01517 void QgsMapCanvas::zoomByFactor( double scaleFactor )
01518 {
01519   if ( mDrawing )
01520   {
01521     return;
01522   }
01523 
01524   QgsRectangle r = mMapRenderer->extent();
01525   r.scale( scaleFactor );
01526   setExtent( r );
01527   refresh();
01528 }
01529 
01530 void QgsMapCanvas::selectionChangedSlot()
01531 {
01532   // Find out which layer it was that sent the signal.
01533   QgsMapLayer *layer = qobject_cast<QgsMapLayer *>( sender() );
01534   emit selectionChanged( layer );
01535   refresh();
01536 }
01537 
01538 void QgsMapCanvas::dragEnterEvent( QDragEnterEvent * e )
01539 {
01540   // By default graphics view delegates the drag events to graphics items.
01541   // But we do not want that and by ignoring the drag enter we let the
01542   // parent (e.g. QgisApp) to handle drops of map layers etc.
01543   e->ignore();
01544 }
01545 
01546 void QgsMapCanvas::crsTransformEnabled( bool enabled )
01547 {
01548   if ( enabled )
01549   {
01550     QgsDebugMsg( "refreshing after reprojection was enabled" );
01551     refresh();
01552     connect( mMapRenderer, SIGNAL( destinationSrsChanged() ), this, SLOT( refresh() ) );
01553   }
01554   else
01555     disconnect( mMapRenderer, SIGNAL( destinationSrsChanged() ), this, SLOT( refresh() ) );
01556 }
01557 
01558 void QgsMapCanvas::mapToolDestroyed()
01559 {
01560   QgsDebugMsg( "maptool destroyed" );
01561   mMapTool = 0;
01562 }
01563 
01564 #ifdef HAVE_TOUCH
01565 bool QgsMapCanvas::event( QEvent * e )
01566 {
01567   bool done = false;
01568   if ( mDrawing )
01569   {
01570     return done;
01571   }
01572   if ( e->type() == QEvent::Gesture )
01573   {
01574     // call handler of current map tool
01575     if ( mMapTool )
01576     {
01577       done = mMapTool->gestureEvent( static_cast<QGestureEvent*>( e ) );
01578     }
01579   }
01580   else
01581   {
01582     // pass other events to base class
01583     done = QGraphicsView::event( e );
01584   }
01585   return done;
01586 }
01587 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines