Skip to content

Commit 90f381b

Browse files
committed
Don't block when canceling canvas render jobs
In some cases canceling render jobs can take a long time. Eg when using database layers over a sloooooow connection, canceling a job can be blocked by minutes while waiting for the first batch of feature fetching to finish. (Since eg postgres features are fetched in batches of 2000 with no opportunity to abort mid-way through this). This meant that while the first render allows the GUI to remain responsive, any subsequent render operations which occured before the first render completes locks up the whole ui until the first render can finish cancellation. With this change, the render cancelation happens with blocking. It means that you can pan and zoom around a map over of slow connection without any ui locks. (cherry-picked from 3b56b79)
1 parent 90fae26 commit 90f381b

12 files changed

+70
-11
lines changed

python/core/qgsmaprenderercustompainterjob.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class QgsMapRendererCustomPainterJob : QgsMapRendererJob
1919

2020
virtual void start();
2121
virtual void cancel();
22+
virtual void cancelWithoutBlocking();
2223
virtual void waitForFinished();
2324
virtual bool isActive() const;
2425
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;

python/core/qgsmaprendererjob.sip

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class QgsMapRendererJob : QObject
5656
//! Does nothing if the rendering is not active.
5757
virtual void cancel() = 0;
5858

59+
virtual void cancelWithoutBlocking() = 0;
60+
5961
//! Block until the job has finished.
6062
virtual void waitForFinished() = 0;
6163

python/core/qgsmaprendererparalleljob.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class QgsMapRendererParallelJob : QgsMapRendererQImageJob
1818

1919
virtual void start();
2020
virtual void cancel();
21+
virtual void cancelWithoutBlocking();
2122
virtual void waitForFinished();
2223
virtual bool isActive() const;
2324

python/core/qgsmaprenderersequentialjob.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ class QgsMapRendererSequentialJob : QgsMapRendererQImageJob
1919

2020
virtual void start();
2121
virtual void cancel();
22+
virtual void cancelWithoutBlocking();
2223
virtual void waitForFinished();
2324
virtual bool isActive() const;
2425

src/core/qgsmaprenderercustompainterjob.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -126,14 +126,7 @@ void QgsMapRendererCustomPainterJob::cancel()
126126

127127
QgsDebugMsg( "QPAINTER cancelling" );
128128
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( futureFinished() ) );
129-
130-
mLabelingRenderContext.setRenderingStopped( true );
131-
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
132-
{
133-
it->context.setRenderingStopped( true );
134-
if ( it->renderer && it->renderer->feedback() )
135-
it->renderer->feedback()->cancel();
136-
}
129+
cancelWithoutBlocking();
137130

138131
QTime t;
139132
t.start();
@@ -144,7 +137,24 @@ void QgsMapRendererCustomPainterJob::cancel()
144137

145138
futureFinished();
146139

147-
QgsDebugMsg( "QPAINTER cancelled" );
140+
QgsDebugMsg( "QPAINTER canceled" );
141+
}
142+
143+
void QgsMapRendererCustomPainterJob::cancelWithoutBlocking()
144+
{
145+
if ( !isActive() )
146+
{
147+
QgsDebugMsg( "QPAINTER not running!" );
148+
return;
149+
}
150+
151+
mLabelingRenderContext.setRenderingStopped( true );
152+
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
153+
{
154+
it->context.setRenderingStopped( true );
155+
if ( it->renderer && it->renderer->feedback() )
156+
it->renderer->feedback()->cancel();
157+
}
148158
}
149159

150160
void QgsMapRendererCustomPainterJob::waitForFinished()

src/core/qgsmaprenderercustompainterjob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class CORE_EXPORT QgsMapRendererCustomPainterJob : public QgsMapRendererJob
3838

3939
virtual void start() override;
4040
virtual void cancel() override;
41+
virtual void cancelWithoutBlocking() override;
4142
virtual void waitForFinished() override;
4243
virtual bool isActive() const override;
4344
virtual QgsLabelingResults* takeLabelingResults() override;

src/core/qgsmaprendererjob.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ class CORE_EXPORT QgsMapRendererJob : public QObject
9696
//! Does nothing if the rendering is not active.
9797
virtual void cancel() = 0;
9898

99+
/**
100+
* Triggers cancelation of the rendering job without blocking. The render job will continue
101+
* to operate until it is able to cancel, at which stage the finished() signal will be emitted.
102+
* Does nothing if the rendering is not active.
103+
*/
104+
virtual void cancelWithoutBlocking() = 0;
105+
99106
//! Block until the job has finished.
100107
virtual void waitForFinished() = 0;
101108

@@ -206,6 +213,7 @@ class CORE_EXPORT QgsMapRendererQImageJob : public QgsMapRendererJob
206213

207214
//! Get a preview/resulting image
208215
virtual QImage renderedImage() = 0;
216+
209217
};
210218

211219

src/core/qgsmaprendererparalleljob.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,28 @@ void QgsMapRendererParallelJob::cancel()
123123
Q_ASSERT( mStatus == Idle );
124124
}
125125

126+
void QgsMapRendererParallelJob::cancelWithoutBlocking()
127+
{
128+
if ( !isActive() )
129+
return;
130+
131+
QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
132+
133+
mLabelingRenderContext.setRenderingStopped( true );
134+
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
135+
{
136+
it->context.setRenderingStopped( true );
137+
if ( it->renderer && it->renderer->feedback() )
138+
it->renderer->feedback()->cancel();
139+
}
140+
141+
if ( mStatus == RenderingLayers )
142+
{
143+
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
144+
connect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
145+
}
146+
}
147+
126148
void QgsMapRendererParallelJob::waitForFinished()
127149
{
128150
if ( !isActive() )

src/core/qgsmaprendererparalleljob.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CORE_EXPORT QgsMapRendererParallelJob : public QgsMapRendererQImageJob
3535

3636
virtual void start() override;
3737
virtual void cancel() override;
38+
virtual void cancelWithoutBlocking() override;
3839
virtual void waitForFinished() override;
3940
virtual bool isActive() const override;
4041

src/core/qgsmaprenderersequentialjob.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,15 @@ void QgsMapRendererSequentialJob::cancel()
8686
Q_ASSERT( !mInternalJob && !mPainter );
8787
}
8888

89+
void QgsMapRendererSequentialJob::cancelWithoutBlocking()
90+
{
91+
if ( !isActive() )
92+
return;
93+
94+
QgsDebugMsg( "sequential - cancel internal" );
95+
mInternalJob->cancelWithoutBlocking();
96+
}
97+
8998
void QgsMapRendererSequentialJob::waitForFinished()
9099
{
91100
if ( !isActive() )

0 commit comments

Comments
 (0)