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