Skip to content

Commit 1110aaf

Browse files
committed
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.
1 parent d49f7ac commit 1110aaf

File tree

5 files changed

+141
-196
lines changed

5 files changed

+141
-196
lines changed

src/core/qgsmaprendererjob.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ void QgsMapRendererSequentialJob::cancel()
5757
{
5858
if (mInternalJob)
5959
{
60+
qDebug("sequential - cancel internal");
6061
mInternalJob->cancel();
6162
delete mInternalJob;
6263
mInternalJob = 0;
@@ -132,7 +133,6 @@ void QgsMapRendererCustomPainterJob::start()
132133
mFutureWatcher.setFuture(mFuture);
133134
}
134135

135-
#include <QApplication>
136136

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

155155
qDebug("QPAINTER cancelled");
156156
}
157+
else
158+
qDebug("QPAINTER not running!");
157159
}
158160

159161
void QgsMapRendererCustomPainterJob::waitForFinished()

src/gui/qgsmapcanvas.cpp

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ email : sherman at mrcc.com
4848
#include "qgsmaptopixel.h"
4949
#include "qgsmapoverviewcanvas.h"
5050
#include "qgsmaprenderer.h"
51+
#include "qgsmaprendererjob.h"
5152
#include "qgsmessagelog.h"
5253
#include "qgsmessageviewer.h"
5354
#include "qgspallabeling.h"
@@ -56,6 +57,7 @@ email : sherman at mrcc.com
5657
#include "qgsvectorlayer.h"
5758
#include <math.h>
5859

60+
5961
/** @deprecated to be deleted, stuff from here should be moved elsewhere */
6062
class QgsMapCanvas::CanvasProperties
6163
{
@@ -82,9 +84,9 @@ class QgsMapCanvas::CanvasProperties
8284
QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
8385
: QGraphicsView( parent )
8486
, mCanvasProperties( new CanvasProperties )
87+
, mJob( 0 )
88+
, mJobCancelled( false )
8589
, mLabelingResults( 0 )
86-
//, mNewSize( QSize() )
87-
//, mPainting( false )
8890
{
8991
setObjectName( name );
9092
mScene = new QGraphicsScene();
@@ -113,7 +115,6 @@ QgsMapCanvas::QgsMapCanvas( QWidget * parent, const char *name )
113115
// create map canvas item which will show the map
114116
mMap = new QgsMapCanvasMap( this );
115117
mScene->addItem( mMap );
116-
mScene->update(); // porting??
117118

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

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

131132
mSettings.setOutputSize( size() );
132-
mMap->resize( size() );
133133
setSceneRect( 0, 0, size().width(), size().height() );
134134
mScene->setSceneRect( QRectF( 0, 0, size().width(), size().height() ) );
135135

136136
moveCanvasContents( true );
137137

138+
connect(&mMapUpdateTimer, SIGNAL( timeout() ), SLOT( mapUpdateTimeout() ) );
139+
mMapUpdateTimer.setInterval( 400 );
140+
138141
#ifdef Q_OS_WIN
139142
// Enable touch event on Windows.
140143
// Qt on Windows needs to be told it can take touch events or else it ignores them.
@@ -171,6 +174,12 @@ QgsMapCanvas::~QgsMapCanvas()
171174
// mCanvasProperties auto-deleted via std::auto_ptr
172175
// CanvasProperties struct has its own dtor for freeing resources
173176

177+
if ( mJob )
178+
{
179+
mJob->cancel();
180+
Q_ASSERT( mJob == 0 );
181+
}
182+
174183
delete mLabelingResults;
175184

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

222231
void QgsMapCanvas::setDirty( bool dirty )
223232
{
224-
mDirty = dirty;
233+
if ( dirty )
234+
refresh();
225235
}
226236

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

234244
bool QgsMapCanvas::isDrawing()
235245
{
236-
return false;
246+
return mJob != 0;
237247
} // isDrawing
238248

239249

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

402-
void QgsMapCanvas::assignLabelingResults( QgsLabelingResults* results )
403-
{
404-
delete mLabelingResults;
405-
mLabelingResults = results;
406-
}
407-
408412

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

425429
void QgsMapCanvas::refresh()
426430
{
427-
mMap->refresh();
431+
stopRendering(); // if any...
432+
433+
qDebug("CANVAS calling update");
434+
mDirty = true;
435+
update();
428436

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

479487
} // refresh
480488

489+
490+
void QgsMapCanvas::rendererJobFinished()
491+
{
492+
qDebug("CANVAS finish! %d", !mJobCancelled );
493+
494+
mMapUpdateTimer.stop();
495+
496+
mDirty = false;
497+
498+
if ( !mJobCancelled )
499+
{
500+
QImage img = mJob->renderedImage();
501+
502+
// emit renderComplete to get our decorations drawn
503+
QPainter p( &img );
504+
emit renderComplete( &p );
505+
p.end();
506+
507+
mMap->setContent( img, mSettings.visibleExtent() );
508+
509+
delete mLabelingResults;
510+
mLabelingResults = mJob->takeLabelingResults();
511+
}
512+
513+
delete mJob;
514+
mJob = 0;
515+
}
516+
517+
void QgsMapCanvas::mapUpdateTimeout()
518+
{
519+
qDebug("CANVAS update timer!");
520+
521+
mMap->setContent( mJob->renderedImage(), mSettings.visibleExtent() );
522+
}
523+
524+
481525
void QgsMapCanvas::stopRendering()
482526
{
483-
// TODO: implement stopping (?)
527+
if ( mJob )
528+
{
529+
qDebug("CANVAS stop rendering!");
530+
mJobCancelled = true;
531+
mJob->cancel();
532+
Q_ASSERT( mJob == 0 ); // no need to delete here: already deleted in finished()
533+
}
484534
}
485535

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

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

612662
void QgsMapCanvas::clear()
613663
{
614-
// Indicate to the next paint event that we need to rebuild the canvas contents
615-
setDirty( true );
616-
664+
refresh();
617665
} // clear
618666

619667

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

9861034
mSettings.setOutputSize( lastSize );
9871035

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

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

10051050
void QgsMapCanvas::paintEvent( QPaintEvent *e )
10061051
{
1052+
qDebug("CANVAS paint()");
1053+
1054+
if ( mDirty )
1055+
{
1056+
if ( mJob )
1057+
{
1058+
qDebug("CANVAS already rendering");
1059+
}
1060+
else
1061+
{
1062+
qDebug("CANVAS need to render");
1063+
1064+
// create the renderer job
1065+
Q_ASSERT( mJob == 0 );
1066+
mJobCancelled = false;
1067+
mJob = new QgsMapRendererSequentialJob( mSettings );
1068+
connect(mJob, SIGNAL( finished() ), SLOT( rendererJobFinished() ) );
1069+
mJob->start();
1070+
1071+
mMapUpdateTimer.start();
1072+
}
1073+
}
1074+
1075+
10071076
QGraphicsView::paintEvent( e );
10081077
} // paintEvent
10091078

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

1315-
mMap->mapDragged( releasePoint - mCanvasProperties->rubberStartPoint );
1316-
13171384
// use start and end box points to calculate the extent
13181385
QgsPoint start = getCoordinateTransform()->toMapCoordinates( mCanvasProperties->rubberStartPoint );
13191386
QgsPoint end = getCoordinateTransform()->toMapCoordinates( releasePoint );

src/gui/qgsmapcanvas.h

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class QgsVectorLayer;
6060

6161
class QgsLabelingResults;
6262
class QgsMapRenderer;
63+
class QgsMapRendererSequentialJob;
6364
class QgsMapSettings;
6465
class QgsMapCanvasMap;
6566
class QgsMapOverviewCanvas;
@@ -136,11 +137,6 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
136137
//! @note added in 2.1
137138
const QgsLabelingResults* labelingResults() const;
138139

139-
//! Store newly generated labeling results (may be null) and take ownership of the object.
140-
//! Only meant for communication with QgsMapCanvasMap
141-
//! @note added in 2.1
142-
void assignLabelingResults( QgsLabelingResults* results );
143-
144140
//! @deprecated since 2.1 - there could be more than just one "map" items
145141
QgsMapCanvasMap* map();
146142

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

157153
//! Clear the map canvas
158-
void clear();
154+
//! @deprecated since 2.1 - use refresh() - clear does the same thing
155+
Q_DECL_DEPRECATED void clear();
159156

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

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

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

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

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

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

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

343+
//! called when a renderer job has finished successfully or when it was cancelled
344+
void rendererJobFinished();
345+
346+
void mapUpdateTimeout();
347+
345348
signals:
346349
/** Let the owner know how far we are with render operations */
347350
//! @deprecated since 2.1 - already unused in 2.0 anyway
@@ -365,9 +368,10 @@ class GUI_EXPORT QgsMapCanvas : public QGraphicsView
365368
being rendered onto a pixmap other than the mapCanvas own pixmap member.
366369
367370
*/
368-
//! @deprecated since 2.1 - anything related to rendering progress is not visible outside of map canvas
371+
//! TODO: deprecate when decorations are reimplemented as map canvas items
372+
//! - anything related to rendering progress is not visible outside of map canvas
369373
//! - additional drawing shall be done directly within the renderer job or independently as a map canvas item
370-
Q_DECL_DEPRECATED void renderComplete( QPainter * );
374+
void renderComplete( QPainter * );
371375

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

504-
/**Resize events that have been ignored because the canvas is busy with
505-
rendering may put their sizes into this list. The canvas then picks up
506-
the last entry in case a lot of resize events arrive in short time*/
507-
QList< QPair<int, int> > mResizeQueue;
508-
509508
//! current layer in legend
510509
QgsMapLayer* mCurrentLayer;
511510

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

531-
QgsLabelingResults* mLabelingResults;
530+
//! Timer that periodically fires while map rendering is in progress to update the visible map
531+
QTimer mMapUpdateTimer;
532+
533+
//! Job that takes care of map rendering in background
534+
QgsMapRendererSequentialJob* mJob;
532535

533-
//! resize canvas size
534-
//QSize mNewSize;
536+
//! Flag determining whether the active job has been cancelled
537+
bool mJobCancelled;
538+
539+
//! Labeling results from the recently rendered map
540+
QgsLabelingResults* mLabelingResults;
535541

536-
//! currently in paint event
537-
//bool mPainting;
538542
}; // class QgsMapCanvas
539543

540544

0 commit comments

Comments
 (0)