20 #include <QApplication>
24 #include <QGraphicsItem>
25 #include <QGraphicsScene>
26 #include <QGraphicsView>
28 #include <QMouseEvent>
30 #include <QPaintEvent>
34 #include <QTextStream>
35 #include <QResizeEvent>
37 #include <QStringList>
38 #include <QWheelEvent>
92 , mRenderer( renderer )
93 , mSyncingExtent( false )
185 : QGraphicsView( parent )
188 , mJobCancelled( false )
189 , mLabelingResults( 0 )
190 , mUseParallelRendering( false )
191 , mDrawRenderingStats( false )
193 , mPreviewEffect( 0 )
194 , mSnappingUtils( 0 )
196 setObjectName( name );
197 mScene =
new QGraphicsScene();
199 setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
200 setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff );
201 mLastExtentIndex = -1;
202 mCurrentLayer = NULL;
205 mLastNonZoomMapTool = NULL;
208 mRefreshScheduled =
false;
215 setMouseTracking(
true );
216 setFocusPolicy( Qt::StrongFocus );
220 mResizeTimer =
new QTimer(
this );
221 mResizeTimer->setSingleShot(
true );
222 connect( mResizeTimer, SIGNAL( timeout() ),
this, SLOT(
refresh() ) );
226 mScene->addItem( mMap );
230 this, SLOT(
readProject(
const QDomDocument & ) ) );
241 QSize s = viewport()->size();
244 setSceneRect( 0, 0, s.width(), s.height() );
245 mScene->setSceneRect( QRectF( 0, 0, s.width(), s.height() ) );
249 connect( &mMapUpdateTimer, SIGNAL( timeout() ), SLOT( mapUpdateTimeout() ) );
250 mMapUpdateTimer.setInterval( 250 );
255 grabGesture( Qt::PinchGesture );
256 viewport()->setAttribute( Qt::WA_AcceptTouchEvents );
260 viewport()->setGraphicsEffect( mPreviewEffect );
262 setInteractive(
false );
276 mLastNonZoomMapTool = NULL;
281 QList<QGraphicsItem*> list = mScene->items();
282 QList<QGraphicsItem*>::iterator it = list.begin();
283 while ( it != list.end() )
285 QGraphicsItem* item = *it;
290 mScene->deleteLater();
299 Q_ASSERT( mJob == 0 );
304 delete mLabelingResults;
335 if ( index >= 0 && index < (
int ) layers.size() )
344 mCurrentLayer =
layer;
382 QStringList layerSet, layerSetOverview;
385 for ( i = 0; i < layers.size(); i++ )
395 layerSet.push_back( lyr.
layer()->
id() );
400 layerSetOverview.push_back( lyr.
layer()->
id() );
406 bool layerSetChanged = layerSetOld != layerSet;
409 if ( layerSetChanged )
411 QgsDebugMsg(
"Layers changed to: " + layerSet.join(
", " ) );
420 disconnect( currentLayer, SIGNAL( repaintRequested() ),
this, SLOT(
refresh() ) );
421 disconnect( currentLayer, SIGNAL( layerCrsChanged() ),
this, SLOT(
layerCrsChange() ) );
436 connect( currentLayer, SIGNAL( repaintRequested() ),
this, SLOT(
refresh() ) );
437 connect( currentLayer, SIGNAL( layerCrsChanged() ),
this, SLOT(
layerCrsChange() ) );
455 const QStringList& layerSetOvOld = mMapOverview->
layerSet();
456 if ( layerSetOvOld != layerSetOverview )
475 mMapOverview, SLOT( destinationSrsChanged() ) );
480 mMapOverview = overview;
488 overview, SLOT( destinationSrsChanged() ) );
525 rect = transform.transformBoundingBox( mSettings.
visibleExtent() );
529 QgsDebugMsg( QString(
"Transform error caught: %1" ).arg( e.
what() ) );
537 QgsDebugMsg(
"refreshing after destination CRS changed" );
550 return mLabelingResults;
582 mUseParallelRendering = enabled;
587 return mUseParallelRendering;
592 mMapUpdateTimer.setInterval( timeMiliseconds );
597 return mMapUpdateTimer.interval();
613 return mCurrentLayer;
621 QgsDebugMsg(
"CANVAS refresh - invalid settings -> nothing to do" );
625 if ( !mRenderFlag || mFrozen )
631 if ( mRefreshScheduled )
637 mRefreshScheduled =
true;
642 QTimer::singleShot( 1,
this, SLOT( refreshMap() ) );
645 void QgsMapCanvas::refreshMap()
647 Q_ASSERT( mRefreshScheduled );
654 mRefreshScheduled =
false;
660 Q_ASSERT( mJob == 0 );
661 mJobCancelled =
false;
662 if ( mUseParallelRendering )
666 connect( mJob, SIGNAL( finished() ), SLOT( rendererJobFinished() ) );
669 QStringList layersForGeometryCache;
670 foreach ( QString
id, mSettings.
layers() )
674 if ( vl->isEditable() )
675 layersForGeometryCache <<
id;
682 mMapUpdateTimer.start();
688 void QgsMapCanvas::rendererJobFinished()
690 QgsDebugMsg( QString(
"CANVAS finish! %1" ).arg( !mJobCancelled ) );
692 mMapUpdateTimer.stop();
700 if ( !mJobCancelled )
704 delete mLabelingResults;
714 if ( settings.value(
"/Map/logCanvasRefreshEvent",
false ).toBool() )
716 QString logMsg =
tr(
"Canvas refresh: %1 ms" ).arg( mJob->
renderingTime() );
720 if ( mDrawRenderingStats )
722 int w = img.width(), h = img.height();
723 QFont fnt = p.font();
726 int lh = p.fontMetrics().height() * 2;
727 QRect r( 0, h - lh, w, lh );
728 p.setPen( Qt::NoPen );
729 p.setBrush( QColor( 0, 0, 0, 110 ) );
731 p.setPen( Qt::white );
732 QString msg = QString(
"%1 :: %2 ms" ).arg( mUseParallelRendering ?
"PARALLEL" :
"SEQUENTIAL" ).arg( mJob->
renderingTime() );
733 p.drawText( r, msg, QTextOption( Qt::AlignCenter ) );
756 QgsRectangle rect( topLeft.
x(), topLeft.
y(), topLeft.
x() + img.width()*res, topLeft.
y() - img.height()*res );
760 void QgsMapCanvas::mapUpdateTimeout()
771 mJobCancelled =
true;
773 Q_ASSERT( mJob == 0 );
787 if ( theQPixmap != NULL )
791 painter.begin( theQPixmap );
798 theQPixmap->save( theFileName, theFormat.toLocal8Bit().data() );
802 mMap->
contentImage().save( theFileName, theFormat.toLocal8Bit().data() );
811 myHeader +=
"0 \r\n";
813 myHeader +=
"0 \r\n";
821 QFileInfo myInfo = QFileInfo( theFileName );
823 QString myWorldFileName = myInfo.absolutePath() +
"/" + myInfo.completeBaseName() +
"." + theFormat +
"w";
824 QFile myWorldFile( myWorldFileName );
825 if ( !myWorldFile.open( QIODevice::WriteOnly ) )
829 QTextStream myStream( &myWorldFile );
830 myStream << myHeader;
863 QgsDebugMsg(
"Empty extent - keeping old scale with new center!" );
872 if ( mLastExtent.size() > 20 )
873 mLastExtent.removeAt( 0 );
876 for (
int i = mLastExtent.size() - 1; i > mLastExtentIndex; i-- )
878 mLastExtent.removeAt( i );
881 mLastExtent.append(
extent() );
884 if ( mLastExtent.size() > 20 )
886 mLastExtent.removeAt( 0 );
890 mLastExtentIndex = mLastExtent.size() - 1;
903 double x = center.
x();
904 double y = center.
y();
932 if ( degrees == current )
965 extent.
scale( 1.05 );
976 if ( mLastExtentIndex > 0 )
979 mSettings.
setExtent( mLastExtent[mLastExtentIndex] );
994 if ( mLastExtentIndex < mLastExtent.size() - 1 )
997 mSettings.
setExtent( mLastExtent[mLastExtentIndex] );
1011 mLastExtent.clear();
1012 mLastExtent.append(
extent() ) ;
1013 mLastExtentIndex = mLastExtent.size() - 1;
1027 if ( layer == NULL )
1033 if ( layer == NULL )
1052 rect.
scale( 1.0, &c );
1069 if ( layer == NULL )
1075 if ( layer == NULL )
1099 QPen pen( Qt::gray );
1107 double dx = qAbs(( currentExtent.
xMaximum() - currentExtent.
xMinimum() ) / 4 );
1108 double dy = qAbs(( currentExtent.
yMaximum() - currentExtent.
yMinimum() ) / 4 );
1154 if ( ! e->isAutoRepeat() )
1161 case Qt::Key_PageUp:
1166 case Qt::Key_PageDown:
1173 mUseParallelRendering = !mUseParallelRendering;
1178 mDrawRenderingStats = !mDrawRenderingStats;
1191 QgsDebugMsg(
"Ignoring key: " + QString::number( e->key() ) );
1223 QgsDebugMsg(
"Ignoring key release: " + QString::number( e->key() ) );
1244 if ( e->button() == Qt::MidButton )
1273 if ( e->button() == Qt::MidButton )
1284 if ( e->button() == Qt::RightButton && mMapTool->
isTransient() )
1286 QgsDebugMsg(
"Right click in map tool zoom or pan, last tool is " +
1287 QString( mLastNonZoomMapTool ?
"not null." :
"null." ) );
1292 if ( mLastNonZoomMapTool
1296 mLastNonZoomMapTool = NULL;
1316 mResizeTimer->start( 500 );
1318 QSize lastSize = viewport()->size();
1323 mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );
1346 QList<QGraphicsItem*> list = mScene->items();
1347 QList<QGraphicsItem*>::iterator it = list.begin();
1348 while ( it != list.end() )
1367 QgsDebugMsg(
"Wheel event delta " + QString::number( e->delta() ) );
1374 if ( QgsApplication::keyboardModifiers() )
1380 switch ( mWheelAction )
1384 if ( e->delta() > 0 )
1398 double scaleFactor = e->delta() > 0 ? 1 / mWheelZoomFactor : mWheelZoomFactor;
1402 QgsPoint newCenter( mousePos.
x() + (( oldCenter.
x() - mousePos.
x() ) * scaleFactor ),
1403 mousePos.
y() + (( oldCenter.
y() - mousePos.
y() ) * scaleFactor ) );
1417 mWheelAction = action;
1418 mWheelZoomFactor = factor;
1438 double scaleFactor = ( zoomIn ? 1 / mWheelZoomFactor : mWheelZoomFactor );
1443 r.
scale( scaleFactor, ¢er );
1466 QPoint xy = e->pos();
1481 disconnect( mMapTool, SIGNAL( destroyed() ),
this, SLOT( mapToolDestroyed() ) );
1490 mLastNonZoomMapTool = mMapTool;
1494 mLastNonZoomMapTool = NULL;
1503 connect( mMapTool, SIGNAL( destroyed() ),
this, SLOT( mapToolDestroyed() ) );
1513 if ( mMapTool && mMapTool == tool )
1519 setCursor( Qt::ArrowCursor );
1522 if ( mLastNonZoomMapTool && mLastNonZoomMapTool == tool )
1524 mLastNonZoomMapTool = NULL;
1535 QBrush bgBrush( theColor );
1536 setBackgroundBrush( bgBrush );
1539 palette.setColor( backgroundRole(), theColor );
1540 setPalette( palette );
1544 mScene->setBackgroundBrush( bgBrush );
1549 return mScene->backgroundBrush().color();
1565 QList<QgsMapLayer*> lst;
1570 lst.append( layer );
1587 QObject *theSender = sender();
1624 QgsDebugMsg(
"Setting map units to " + QString::number( static_cast<int>( u ) ) );
1643 mRenderFlag = theFlag;
1654 void QgsMapCanvas::connectNotify(
const char * signal )
1657 QgsDebugMsg(
"QgsMapCanvas connected to " + QString( signal ) );
1667 foreach ( QString layerID, mSettings.
layers() )
1700 double dx = end.
x() - start.
x();
1701 double dy = end.
y() - start.
y();
1703 c.
set( c.
x() - dx, c.
y() - dy );
1723 setSceneRect( -pnt.x(), -pnt.y(), viewport()->size().width(), viewport()->size().height() );
1728 Q_UNUSED( mapLayer );
1738 if ( !mPreviewEffect )
1743 mPreviewEffect->setEnabled( previewEnabled );
1748 if ( !mPreviewEffect )
1753 return mPreviewEffect->isEnabled();
1758 if ( !mPreviewEffect )
1763 mPreviewEffect->
setMode( mode );
1768 if ( !mPreviewEffect )
1773 return mPreviewEffect->
mode();
1778 if ( !mSnappingUtils )
1784 return mSnappingUtils;
1789 mSnappingUtils = utils;
1794 QDomNodeList nodes = doc.elementsByTagName(
"mapcanvas" );
1795 if ( nodes.count() )
1797 QDomNode node = nodes.item( 0 );
1812 QgsDebugMsg(
"Couldn't read mapcanvas information from project" );
1820 QDomNodeList nl = doc.elementsByTagName(
"qgis" );
1823 QgsDebugMsg(
"Unable to find qgis element in project file" );
1826 QDomNode qgisNode = nl.item( 0 );
1828 QDomElement mapcanvasNode = doc.createElement(
"mapcanvas" );
1829 qgisNode.appendChild( mapcanvasNode );
1831 mSettings.
writeXML( mapcanvasNode, doc );
1845 QString settingsString =
"/Projections/" + srcAuthId +
"//" + destAuthId;
1846 QVariant defaultSrcTransform = s.value( settingsString +
"_srcTransform" );
1847 QVariant defaultDestTransform = s.value( settingsString +
"_destTransform" );
1848 if ( defaultSrcTransform.isValid() && defaultDestTransform.isValid() )
1858 if ( !s.value(
"/Projections/showDatumTransformDialog",
false ).toBool() )
1868 if ( dt.size() < 2 )
1876 if ( d.exec() == QDialog::Accepted )
1878 int srcTransform = -1;
1879 int destTransform = -1;
1880 QList<int> t = d.selectedDatumTransform();
1883 srcTransform = t.at( 0 );
1887 destTransform = t.at( 1 );
1891 if ( d.rememberSelection() )
1893 s.setValue( settingsString +
"_srcTransform", srcTransform );
1894 s.setValue( settingsString +
"_destTransform", destTransform );
1907 r.
scale( scaleFactor, center );
1928 void QgsMapCanvas::mapToolDestroyed()
1935 bool QgsMapCanvas::event( QEvent * e )
1938 if ( e->type() == QEvent::Gesture )
1943 done = mMapTool->gestureEvent( static_cast<QGestureEvent*>( e ) );
1949 done = QGraphicsView::event( e );
1957 return QSettings().value(
"/qgis/canvasRotation",
true ).toBool();
1962 QSettings().setValue(
"/qgis/canvasRotation", enable );