Quantum GIS API Documentation
1.8
|
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, ¢er ); 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