|
QGIS API Documentation
master-6227475
|
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, ¢er ); 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