Skip to content
Permalink
Browse files

Do map rendering inside of QgsMapCanvas

QgsMapCanvasMap is now just a simple map canvas item storing an image,
all rendering logic has been moved to QgsMapCanvas.
Restored functionality of map decorations and cancellation of rendering.
When map is going to be refreshed, the old rendered map stays visible
for a small amount of time (scaled) and then it is replaced by the new map.
  • Loading branch information
wonder-sk committed Nov 15, 2013
1 parent d49f7ac commit 1110aafa432681e13aadd860a64ec78092b80675
Showing with 141 additions and 196 deletions.
  1. +3 −1 src/core/qgsmaprendererjob.cpp
  2. +92 −25 src/gui/qgsmapcanvas.cpp
  3. +27 −23 src/gui/qgsmapcanvas.h
  4. +9 −117 src/gui/qgsmapcanvasmap.cpp
  5. +10 −30 src/gui/qgsmapcanvasmap.h
@@ -57,6 +57,7 @@ void QgsMapRendererSequentialJob::cancel()
{
if (mInternalJob)
{
qDebug("sequential - cancel internal");
mInternalJob->cancel();
delete mInternalJob;
mInternalJob = 0;
@@ -132,7 +133,6 @@ void QgsMapRendererCustomPainterJob::start()
mFutureWatcher.setFuture(mFuture);
}

#include <QApplication>

void QgsMapRendererCustomPainterJob::cancel()
{
@@ -154,6 +154,8 @@ void QgsMapRendererCustomPainterJob::cancel()

qDebug("QPAINTER cancelled");
}
else
qDebug("QPAINTER not running!");
}

void QgsMapRendererCustomPainterJob::waitForFinished()
@@ -48,6 +48,7 @@ email : sherman at mrcc.com
#include "qgsmaptopixel.h"
#include "qgsmapoverviewcanvas.h"
#include "qgsmaprenderer.h"
#include "qgsmaprendererjob.h"
#include "qgsmessagelog.h"
#include "qgsmessageviewer.h"
#include "qgspallabeling.h"
@@ -56,6 +57,7 @@ email : sherman at mrcc.com
#include "qgsvectorlayer.h"
#include <math.h>


/** @deprecated to be deleted, stuff from here should be moved elsewhere */
class QgsMapCanvas::CanvasProperties
{
@@ -82,9 +84,9 @@ class QgsMapCanvas::CanvasProperties
QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
: QGraphicsView( parent )
, mCanvasProperties( new CanvasProperties )
, mJob( 0 )
, mJobCancelled( false )
, mLabelingResults( 0 )
//, mNewSize( QSize() )
//, mPainting( false )
{
setObjectName( name );
mScene = new QGraphicsScene();
@@ -113,7 +115,6 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
// create map canvas item which will show the map
mMap = new QgsMapCanvasMap( this );
mScene->addItem( mMap );
mScene->update(); // porting??

connect( mMapRenderer, SIGNAL( drawError( QgsMapLayer* ) ), this, SLOT( showError( QgsMapLayer* ) ) );

@@ -129,12 +130,14 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
mSettings.setFlag( QgsMapSettings::DrawEditingInfo );

mSettings.setOutputSize( size() );
mMap->resize( size() );
setSceneRect( 0, 0, size().width(), size().height() );
mScene->setSceneRect( QRectF( 0, 0, size().width(), size().height() ) );

moveCanvasContents( true );

connect(&mMapUpdateTimer, SIGNAL( timeout() ), SLOT( mapUpdateTimeout() ) );
mMapUpdateTimer.setInterval( 400 );

#ifdef Q_OS_WIN
// Enable touch event on Windows.
// Qt on Windows needs to be told it can take touch events or else it ignores them.
@@ -171,6 +174,12 @@ QgsMapCanvas::~QgsMapCanvas()
// mCanvasProperties auto-deleted via std::auto_ptr
// CanvasProperties struct has its own dtor for freeing resources

if ( mJob )
{
mJob->cancel();
Q_ASSERT( mJob == 0 );
}

delete mLabelingResults;

} // dtor
@@ -221,7 +230,8 @@ double QgsMapCanvas::scale()

void QgsMapCanvas::setDirty( bool dirty )
{
mDirty = dirty;
if ( dirty )
refresh();
}

bool QgsMapCanvas::isDirty() const
@@ -233,7 +243,7 @@ bool QgsMapCanvas::isDirty() const

bool QgsMapCanvas::isDrawing()
{
return false;
return mJob != 0;
} // isDrawing


@@ -399,12 +409,6 @@ const QgsLabelingResults *QgsMapCanvas::labelingResults() const
return mLabelingResults;
}

void QgsMapCanvas::assignLabelingResults( QgsLabelingResults* results )
{
delete mLabelingResults;
mLabelingResults = results;
}


void QgsMapCanvas::updateOverview()
{
@@ -424,7 +428,11 @@ QgsMapLayer* QgsMapCanvas::currentLayer()

void QgsMapCanvas::refresh()
{
mMap->refresh();
stopRendering(); // if any...

qDebug("CANVAS calling update");
mDirty = true;
update();

/*
// we can't draw again if already drawing...
@@ -478,9 +486,51 @@ void QgsMapCanvas::refresh()

} // refresh


void QgsMapCanvas::rendererJobFinished()
{
qDebug("CANVAS finish! %d", !mJobCancelled );

mMapUpdateTimer.stop();

mDirty = false;

if ( !mJobCancelled )
{
QImage img = mJob->renderedImage();

// emit renderComplete to get our decorations drawn
QPainter p( &img );
emit renderComplete( &p );
p.end();

mMap->setContent( img, mSettings.visibleExtent() );

delete mLabelingResults;
mLabelingResults = mJob->takeLabelingResults();
}

delete mJob;
mJob = 0;
}

void QgsMapCanvas::mapUpdateTimeout()
{
qDebug("CANVAS update timer!");

mMap->setContent( mJob->renderedImage(), mSettings.visibleExtent() );
}


void QgsMapCanvas::stopRendering()
{
// TODO: implement stopping (?)
if ( mJob )
{
qDebug("CANVAS stop rendering!");
mJobCancelled = true;
mJob->cancel();
Q_ASSERT( mJob == 0 ); // no need to delete here: already deleted in finished()
}
}

void QgsMapCanvas::updateMap()
@@ -507,11 +557,11 @@ void QgsMapCanvas::saveAsImage( QString theFileName, QPixmap * theQPixmap, QStri
else //use the map view
{
// TODO[MD]: fix
QPixmap *pixmap = dynamic_cast<QPixmap *>( &mMap->paintDevice() );
if ( !pixmap )
QImage *img = dynamic_cast<QImage *>( &mMap->paintDevice() );
if ( !img)
return;

pixmap->save( theFileName, theFormat.toLocal8Bit().data() );
img->save( theFileName, theFormat.toLocal8Bit().data() );
}
//create a world file to go with the image...
QgsRectangle myRect = mapSettings().visibleExtent();
@@ -611,9 +661,7 @@ void QgsMapCanvas::updateScale()

void QgsMapCanvas::clear()
{
// Indicate to the next paint event that we need to rebuild the canvas contents
setDirty( true );

refresh();
} // clear


@@ -985,9 +1033,6 @@ void QgsMapCanvas::resizeEvent( QResizeEvent * e )

mSettings.setOutputSize( lastSize );

//set map size before scene size helps keep scene indexes updated properly
// this was the cause of rubberband artifacts
mMap->resize( lastSize );
mScene->setSceneRect( QRectF( 0, 0, lastSize.width(), lastSize.height() ) );

moveCanvasContents( true );
@@ -1004,6 +1049,30 @@ void QgsMapCanvas::resizeEvent( QResizeEvent * e )

void QgsMapCanvas::paintEvent( QPaintEvent *e )
{
qDebug("CANVAS paint()");

if ( mDirty )
{
if ( mJob )
{
qDebug("CANVAS already rendering");
}
else
{
qDebug("CANVAS need to render");

// create the renderer job
Q_ASSERT( mJob == 0 );
mJobCancelled = false;
mJob = new QgsMapRendererSequentialJob( mSettings );
connect(mJob, SIGNAL( finished() ), SLOT( rendererJobFinished() ) );
mJob->start();

mMapUpdateTimer.start();
}
}


QGraphicsView::paintEvent( e );
} // paintEvent

@@ -1312,8 +1381,6 @@ void QgsMapCanvas::panActionEnd( QPoint releasePoint )
// move map image and other items to standard position
moveCanvasContents( true ); // true means reset

mMap->mapDragged( releasePoint - mCanvasProperties->rubberStartPoint );

// use start and end box points to calculate the extent
QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );
@@ -60,6 +60,7 @@ class QgsVectorLayer;

class QgsLabelingResults;
class QgsMapRenderer;
class QgsMapRendererSequentialJob;
class QgsMapSettings;
class QgsMapCanvasMap;
class QgsMapOverviewCanvas;
@@ -136,11 +137,6 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! @note added in 2.1
const QgsLabelingResults* labelingResults() const;

//! Store newly generated labeling results (may be null) and take ownership of the object.
//! Only meant for communication with QgsMapCanvasMap
//! @note added in 2.1
void assignLabelingResults( QgsLabelingResults* results );

//! @deprecated since 2.1 - there could be more than just one "map" items
QgsMapCanvasMap* map();

@@ -155,7 +151,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
double scale();

//! Clear the map canvas
void clear();
//! @deprecated since 2.1 - use refresh() - clear does the same thing
Q_DECL_DEPRECATED void clear();

//! Returns the mapUnitsPerPixel (map units per pixel) for the canvas
double mapUnitsPerPixel() const;
@@ -237,7 +234,8 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
bool isFrozen();

//! Flag the canvas as dirty and needed a refresh
void setDirty( bool _dirty );
//! @deprecated since 2.1 - use refresh() to trigger a refresh (clients should not decide explicitly whether canvas is dirty or not)
Q_DECL_DEPRECATED void setDirty( bool _dirty );

//! Return the state of the canvas (dirty or not)
bool isDirty() const;
@@ -251,7 +249,7 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! Get the current coordinate transform
const QgsMapToPixel* getCoordinateTransform();

//! @deprecated in 2.1 - always returns false
//! Find out whether rendering is in progress
bool isDrawing();

//! returns current layer (set by legend widget)
@@ -325,9 +323,9 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! @deprecated in 2.1 - does nothing - kept for API compatibility
Q_DECL_DEPRECATED void updateMap();

//! added in 2.1
//! @note probably it is not necessary to allow any client to stop rendering - should be handled just be canvas
Q_DECL_DEPRECATED void stopRendering();
//! stop rendering (if there is any right now)
//! @note added in 2.1
void stopRendering();

//! show whatever error is exposed by the QgsMapLayer.
void showError( QgsMapLayer * mapLayer );
@@ -342,6 +340,11 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! called when current maptool is destroyed
void mapToolDestroyed();

//! called when a renderer job has finished successfully or when it was cancelled
void rendererJobFinished();

void mapUpdateTimeout();

signals:
/** Let the owner know how far we are with render operations */
//! @deprecated since 2.1 - already unused in 2.0 anyway
@@ -365,9 +368,10 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
being rendered onto a pixmap other than the mapCanvas own pixmap member.
*/
//! @deprecated since 2.1 - anything related to rendering progress is not visible outside of map canvas
//! TODO: deprecate when decorations are reimplemented as map canvas items
//! - anything related to rendering progress is not visible outside of map canvas
//! - additional drawing shall be done directly within the renderer job or independently as a map canvas item
Q_DECL_DEPRECATED void renderComplete( QPainter * );
void renderComplete( QPainter * );

/** Emitted when canvas finished a refresh request.
\note Added in 2.0 */
@@ -501,11 +505,6 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! determines whether user has requested to suppress rendering
bool mRenderFlag;

/**Resize events that have been ignored because the canvas is busy with
rendering may put their sizes into this list. The canvas then picks up
the last entry in case a lot of resize events arrive in short time*/
QList< QPair<int, int> > mResizeQueue;

//! current layer in legend
QgsMapLayer* mCurrentLayer;

@@ -528,13 +527,18 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
//! Mouse wheel action
WheelAction mWheelAction;

QgsLabelingResults* mLabelingResults;
//! Timer that periodically fires while map rendering is in progress to update the visible map
QTimer mMapUpdateTimer;

//! Job that takes care of map rendering in background
QgsMapRendererSequentialJob* mJob;

//! resize canvas size
//QSize mNewSize;
//! Flag determining whether the active job has been cancelled
bool mJobCancelled;

//! Labeling results from the recently rendered map
QgsLabelingResults* mLabelingResults;

//! currently in paint event
//bool mPainting;
}; // class QgsMapCanvas


0 comments on commit 1110aaf

Please sign in to comment.
You can’t perform that action at this time.