Skip to content

Commit 436b05e

Browse files
committedJun 22, 2014
Move QgsRendererJob subclasses to new files (no code changes)
1 parent cfe43c3 commit 436b05e

20 files changed

+1050
-929
lines changed
 

‎python/core/core.sip

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,10 @@
5151
%Include qgsmaplayerrenderer.sip
5252
%Include qgsmaprenderer.sip
5353
%Include qgsmaprenderercache.sip
54+
%Include qgsmaprenderercustompainterjob.sip
5455
%Include qgsmaprendererjob.sip
56+
%Include qgsmaprendererparalleljob.sip
57+
%Include qgsmaprenderersequentialjob.sip
5558
%Include qgsmapsettings.sip
5659
%Include qgsmaptopixel.sip
5760
%Include qgsmapunitscale.sip
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
2+
/** job implementation that renders everything sequentially using a custom painter.
3+
* The returned image is always invalid (because there is none available).
4+
*/
5+
class QgsMapRendererCustomPainterJob : QgsMapRendererJob
6+
{
7+
%TypeHeaderCode
8+
#include <qgsmaprenderercustompainterjob.h>
9+
%End
10+
11+
public:
12+
QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter );
13+
~QgsMapRendererCustomPainterJob();
14+
15+
virtual void start();
16+
virtual void cancel();
17+
virtual void waitForFinished();
18+
virtual bool isActive() const;
19+
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
20+
21+
//! @note not available in python bindings
22+
// const LayerRenderJobs& jobs() const { return mLayerJobs; }
23+
24+
/**
25+
* Wait for the job to be finished - and keep the thread's event loop running while waiting.
26+
*
27+
* With a call to waitForFinished(), the waiting is done with a synchronization primitive
28+
* and does not involve processing of messages. That may cause issues to code which requires
29+
* some events to be handled in the main thread. Some plugins hooking into the rendering
30+
* pipeline may require this in order to work properly - for example, OpenLayers plugin
31+
* which uses a QWebPage in the main thread.
32+
*
33+
* Ideally the "wait for finished" method should not be used at all. The code triggering
34+
* rendering should not need to actively wait for rendering to finish.
35+
*/
36+
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );
37+
38+
/**
39+
* Render the map synchronously in this thread. The function does not return until the map
40+
* is completely rendered.
41+
*
42+
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
43+
* Users are discouraged to use this method unless they have a strong reason for doing it.
44+
* The synchronous rendering blocks the main thread, making the application unresponsive.
45+
* Also, it is not possible to cancel rendering while it is in progress.
46+
*/
47+
void renderSynchronously();
48+
49+
protected slots:
50+
void futureFinished();
51+
52+
protected:
53+
static void staticRender( QgsMapRendererCustomPainterJob* self ); // function to be used within the thread
54+
55+
// these methods are called within worker thread
56+
void doRender();
57+
};

‎python/core/qgsmaprendererjob.sip

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -115,126 +115,3 @@ class QgsMapRendererQImageJob : QgsMapRendererJob
115115
//! Get a preview/resulting image
116116
virtual QImage renderedImage() = 0;
117117
};
118-
119-
120-
121-
/** job implementation that renders everything sequentially in one thread */
122-
class QgsMapRendererSequentialJob : QgsMapRendererQImageJob
123-
{
124-
%TypeHeaderCode
125-
#include <qgsmaprendererjob.h>
126-
%End
127-
128-
public:
129-
QgsMapRendererSequentialJob( const QgsMapSettings& settings );
130-
~QgsMapRendererSequentialJob();
131-
132-
virtual void start();
133-
virtual void cancel();
134-
virtual void waitForFinished();
135-
virtual bool isActive() const;
136-
137-
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
138-
139-
// from QgsMapRendererJobWithPreview
140-
virtual QImage renderedImage();
141-
142-
public slots:
143-
144-
void internalFinished();
145-
};
146-
147-
148-
149-
150-
/** job implementation that renders all layers in parallel */
151-
class QgsMapRendererParallelJob : QgsMapRendererQImageJob
152-
{
153-
%TypeHeaderCode
154-
#include <qgsmaprendererjob.h>
155-
%End
156-
157-
public:
158-
QgsMapRendererParallelJob( const QgsMapSettings& settings );
159-
~QgsMapRendererParallelJob();
160-
161-
virtual void start();
162-
virtual void cancel();
163-
virtual void waitForFinished();
164-
virtual bool isActive() const;
165-
166-
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
167-
168-
// from QgsMapRendererJobWithPreview
169-
virtual QImage renderedImage();
170-
171-
protected slots:
172-
//! layers are rendered, labeling is still pending
173-
void renderLayersFinished();
174-
//! all rendering is finished, including labeling
175-
void renderingFinished();
176-
177-
protected:
178-
179-
static void renderLayerStatic( LayerRenderJob& job );
180-
static void renderLabelsStatic( QgsMapRendererParallelJob* self );
181-
};
182-
183-
184-
185-
/** job implementation that renders everything sequentially using a custom painter.
186-
* The returned image is always invalid (because there is none available).
187-
*/
188-
class QgsMapRendererCustomPainterJob : QgsMapRendererJob
189-
{
190-
%TypeHeaderCode
191-
#include <qgsmaprendererjob.h>
192-
%End
193-
194-
public:
195-
QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter );
196-
~QgsMapRendererCustomPainterJob();
197-
198-
virtual void start();
199-
virtual void cancel();
200-
virtual void waitForFinished();
201-
virtual bool isActive() const;
202-
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
203-
204-
//! @note not available in python bindings
205-
// const LayerRenderJobs& jobs() const { return mLayerJobs; }
206-
207-
/**
208-
* Wait for the job to be finished - and keep the thread's event loop running while waiting.
209-
*
210-
* With a call to waitForFinished(), the waiting is done with a synchronization primitive
211-
* and does not involve processing of messages. That may cause issues to code which requires
212-
* some events to be handled in the main thread. Some plugins hooking into the rendering
213-
* pipeline may require this in order to work properly - for example, OpenLayers plugin
214-
* which uses a QWebPage in the main thread.
215-
*
216-
* Ideally the "wait for finished" method should not be used at all. The code triggering
217-
* rendering should not need to actively wait for rendering to finish.
218-
*/
219-
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );
220-
221-
/**
222-
* Render the map synchronously in this thread. The function does not return until the map
223-
* is completely rendered.
224-
*
225-
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
226-
* Users are discouraged to use this method unless they have a strong reason for doing it.
227-
* The synchronous rendering blocks the main thread, making the application unresponsive.
228-
* Also, it is not possible to cancel rendering while it is in progress.
229-
*/
230-
void renderSynchronously();
231-
232-
protected slots:
233-
void futureFinished();
234-
235-
protected:
236-
static void staticRender( QgsMapRendererCustomPainterJob* self ); // function to be used within the thread
237-
238-
// these methods are called within worker thread
239-
void doRender();
240-
};
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
/** job implementation that renders all layers in parallel */
3+
class QgsMapRendererParallelJob : QgsMapRendererQImageJob
4+
{
5+
%TypeHeaderCode
6+
#include <qgsmaprendererparalleljob.h>
7+
%End
8+
9+
public:
10+
QgsMapRendererParallelJob( const QgsMapSettings& settings );
11+
~QgsMapRendererParallelJob();
12+
13+
virtual void start();
14+
virtual void cancel();
15+
virtual void waitForFinished();
16+
virtual bool isActive() const;
17+
18+
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
19+
20+
// from QgsMapRendererJobWithPreview
21+
virtual QImage renderedImage();
22+
23+
protected slots:
24+
//! layers are rendered, labeling is still pending
25+
void renderLayersFinished();
26+
//! all rendering is finished, including labeling
27+
void renderingFinished();
28+
29+
protected:
30+
31+
static void renderLayerStatic( LayerRenderJob& job );
32+
static void renderLabelsStatic( QgsMapRendererParallelJob* self );
33+
};
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
3+
/** job implementation that renders everything sequentially in one thread */
4+
class QgsMapRendererSequentialJob : QgsMapRendererQImageJob
5+
{
6+
%TypeHeaderCode
7+
#include <qgsmaprenderersequentialjob.h>
8+
%End
9+
10+
public:
11+
QgsMapRendererSequentialJob( const QgsMapSettings& settings );
12+
~QgsMapRendererSequentialJob();
13+
14+
virtual void start();
15+
virtual void cancel();
16+
virtual void waitForFinished();
17+
virtual bool isActive() const;
18+
19+
virtual QgsLabelingResults* takeLabelingResults() /Transfer/;
20+
21+
// from QgsMapRendererJobWithPreview
22+
virtual QImage renderedImage();
23+
24+
public slots:
25+
26+
void internalFinished();
27+
};

‎src/app/maprenderertest.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
#include "qgsmapsettings.h"
1010
#include "qgsmaplayer.h"
1111

12-
#include "qgsmaprendererjob.h"
12+
#include "qgsmaprenderersequentialjob.h"
1313

1414
class TestWidget : public QLabel
1515
{

‎src/core/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ SET(QGIS_CORE_SRCS
77
qgsxmlutils.cpp
88
qgsmapsettings.cpp
99
qgsmaprendererjob.cpp
10+
qgsmaprenderercustompainterjob.cpp
11+
qgsmaprendererparalleljob.cpp
12+
qgsmaprenderersequentialjob.cpp
1013
qgsvectorlayerrenderer.cpp
1114
raster/qgsrasterlayerrenderer.cpp
1215

@@ -323,6 +326,9 @@ SET(QGIS_CORE_MOC_HDRS
323326

324327
qgsmaprenderercache.h
325328
qgsmaprendererjob.h
329+
qgsmaprenderercustompainterjob.h
330+
qgsmaprendererparalleljob.h
331+
qgsmaprenderersequentialjob.h
326332

327333
qgsapplication.h
328334
qgsbrowsermodel.h

‎src/core/composer/qgscomposermap.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "qgscoordinatetransform.h"
2121
#include "qgslogger.h"
2222
#include "qgsmaprenderer.h"
23-
#include "qgsmaprendererjob.h"
23+
#include "qgsmaprenderercustompainterjob.h"
2424
#include "qgsmaplayerregistry.h"
2525
#include "qgsmaptopixel.h"
2626
#include "qgsproject.h"
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
/***************************************************************************
2+
qgsmaprenderercustompainterjob.cpp
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsmaprenderercustompainterjob.h"
17+
18+
#include "qgslogger.h"
19+
#include "qgsmaplayerregistry.h"
20+
#include "qgsmaplayerrenderer.h"
21+
#include "qgspallabeling.h"
22+
23+
24+
QgsMapRendererCustomPainterJob::QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter )
25+
: QgsMapRendererJob( settings )
26+
, mPainter( painter )
27+
, mLabelingEngine( 0 )
28+
, mActive( false )
29+
, mRenderSynchronously( false )
30+
{
31+
QgsDebugMsg( "QPAINTER construct" );
32+
}
33+
34+
QgsMapRendererCustomPainterJob::~QgsMapRendererCustomPainterJob()
35+
{
36+
QgsDebugMsg( "QPAINTER destruct" );
37+
Q_ASSERT( !mFutureWatcher.isRunning() );
38+
//cancel();
39+
40+
delete mLabelingEngine;
41+
mLabelingEngine = 0;
42+
}
43+
44+
void QgsMapRendererCustomPainterJob::start()
45+
{
46+
if ( isActive() )
47+
return;
48+
49+
mRenderingStart.start();
50+
51+
mActive = true;
52+
53+
mErrors.clear();
54+
55+
QgsDebugMsg( "QPAINTER run!" );
56+
57+
QgsDebugMsg( "Preparing list of layer jobs for rendering" );
58+
QTime prepareTime;
59+
prepareTime.start();
60+
61+
// clear the background
62+
mPainter->fillRect( 0, 0, mSettings.outputSize().width(), mSettings.outputSize().height(), mSettings.backgroundColor() );
63+
64+
mPainter->setRenderHint( QPainter::Antialiasing, mSettings.testFlag( QgsMapSettings::Antialiasing ) );
65+
66+
QPaintDevice* thePaintDevice = mPainter->device();
67+
68+
QString errMsg = QString( "pre-set DPI not equal to painter's DPI (%1 vs %2)" ).arg( thePaintDevice->logicalDpiX() ).arg( mSettings.outputDpi() );
69+
Q_ASSERT_X( thePaintDevice->logicalDpiX() == mSettings.outputDpi(), "Job::startRender()", errMsg.toAscii().data() );
70+
71+
delete mLabelingEngine;
72+
mLabelingEngine = 0;
73+
74+
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) )
75+
{
76+
mLabelingEngine = new QgsPalLabeling;
77+
mLabelingEngine->loadEngineSettings();
78+
mLabelingEngine->init( mSettings );
79+
}
80+
81+
mLayerJobs = prepareJobs( mPainter, mLabelingEngine );
82+
83+
QgsDebugMsg( "Rendering prepared in (seconds): " + QString( "%1" ).arg( prepareTime.elapsed() / 1000.0 ) );
84+
85+
if ( mRenderSynchronously )
86+
{
87+
// do the rendering right now!
88+
doRender();
89+
return;
90+
}
91+
92+
// now we are ready to start rendering!
93+
connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( futureFinished() ) );
94+
95+
mFuture = QtConcurrent::run( staticRender, this );
96+
mFutureWatcher.setFuture( mFuture );
97+
}
98+
99+
100+
void QgsMapRendererCustomPainterJob::cancel()
101+
{
102+
if ( !isActive() )
103+
{
104+
QgsDebugMsg( "QPAINTER not running!" );
105+
return;
106+
}
107+
108+
QgsDebugMsg( "QPAINTER cancelling" );
109+
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( futureFinished() ) );
110+
111+
mLabelingRenderContext.setRenderingStopped( true );
112+
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
113+
{
114+
it->context.setRenderingStopped( true );
115+
}
116+
117+
QTime t;
118+
t.start();
119+
120+
mFutureWatcher.waitForFinished();
121+
122+
QgsDebugMsg( QString( "QPAINER cancel waited %1 ms" ).arg( t.elapsed() / 1000.0 ) );
123+
124+
futureFinished();
125+
126+
QgsDebugMsg( "QPAINTER cancelled" );
127+
}
128+
129+
void QgsMapRendererCustomPainterJob::waitForFinished()
130+
{
131+
if ( !isActive() )
132+
return;
133+
134+
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( futureFinished() ) );
135+
136+
QTime t;
137+
t.start();
138+
139+
mFutureWatcher.waitForFinished();
140+
141+
QgsDebugMsg( QString( "waitForFinished: %1 ms" ).arg( t.elapsed() / 1000.0 ) );
142+
143+
futureFinished();
144+
}
145+
146+
bool QgsMapRendererCustomPainterJob::isActive() const
147+
{
148+
return mActive;
149+
}
150+
151+
152+
QgsLabelingResults* QgsMapRendererCustomPainterJob::takeLabelingResults()
153+
{
154+
return mLabelingEngine ? mLabelingEngine->takeResults() : 0;
155+
}
156+
157+
158+
void QgsMapRendererCustomPainterJob::waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags )
159+
{
160+
QEventLoop loop;
161+
connect( &mFutureWatcher, SIGNAL( finished() ), &loop, SLOT( quit() ) );
162+
loop.exec( flags );
163+
}
164+
165+
166+
void QgsMapRendererCustomPainterJob::renderSynchronously()
167+
{
168+
mRenderSynchronously = true;
169+
start();
170+
futureFinished();
171+
mRenderSynchronously = false;
172+
}
173+
174+
175+
void QgsMapRendererCustomPainterJob::futureFinished()
176+
{
177+
mActive = false;
178+
mRenderingTime = mRenderingStart.elapsed();
179+
QgsDebugMsg( "QPAINTER futureFinished" );
180+
181+
// final cleanup
182+
cleanupJobs( mLayerJobs );
183+
184+
emit finished();
185+
}
186+
187+
188+
void QgsMapRendererCustomPainterJob::staticRender( QgsMapRendererCustomPainterJob* self )
189+
{
190+
self->doRender();
191+
}
192+
193+
void QgsMapRendererCustomPainterJob::doRender()
194+
{
195+
QgsDebugMsg( "Starting to render layer stack." );
196+
QTime renderTime;
197+
renderTime.start();
198+
199+
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
200+
{
201+
LayerRenderJob& job = *it;
202+
203+
if ( job.context.renderingStopped() )
204+
break;
205+
206+
if ( job.context.useAdvancedEffects() )
207+
{
208+
// Set the QPainter composition mode so that this layer is rendered using
209+
// the desired blending mode
210+
mPainter->setCompositionMode( job.blendMode );
211+
}
212+
213+
if ( !job.cached )
214+
job.renderer->render();
215+
216+
if ( job.img )
217+
{
218+
// If we flattened this layer for alternate blend modes, composite it now
219+
mPainter->drawImage( 0, 0, *job.img );
220+
}
221+
222+
}
223+
224+
QgsDebugMsg( "Done rendering map layers" );
225+
226+
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) && !mLabelingRenderContext.renderingStopped() )
227+
drawLabeling( mSettings, mLabelingRenderContext, mLabelingEngine, mPainter );
228+
229+
QgsDebugMsg( "Rendering completed in (seconds): " + QString( "%1" ).arg( renderTime.elapsed() / 1000.0 ) );
230+
}
231+
232+
233+
void QgsMapRendererJob::drawLabeling( const QgsMapSettings& settings, QgsRenderContext& renderContext, QgsPalLabeling* labelingEngine, QPainter* painter )
234+
{
235+
QgsDebugMsg( "Draw labeling start" );
236+
237+
QTime t;
238+
t.start();
239+
240+
// Reset the composition mode before rendering the labels
241+
painter->setCompositionMode( QPainter::CompositionMode_SourceOver );
242+
243+
// TODO: this is not ideal - we could override rendering stopped flag that has been set in meanwhile
244+
renderContext = QgsRenderContext::fromMapSettings( settings );
245+
renderContext.setPainter( painter );
246+
renderContext.setLabelingEngine( labelingEngine );
247+
248+
// old labeling - to be removed at some point...
249+
drawOldLabeling( settings, renderContext );
250+
251+
drawNewLabeling( settings, renderContext, labelingEngine );
252+
253+
QgsDebugMsg( QString( "Draw labeling took (seconds): %1" ).arg( t.elapsed() / 1000. ) );
254+
}
255+
256+
257+
void QgsMapRendererJob::drawOldLabeling( const QgsMapSettings& settings, QgsRenderContext& renderContext )
258+
{
259+
// render all labels for vector layers in the stack, starting at the base
260+
QListIterator<QString> li( settings.layers() );
261+
li.toBack();
262+
while ( li.hasPrevious() )
263+
{
264+
if ( renderContext.renderingStopped() )
265+
{
266+
break;
267+
}
268+
269+
QString layerId = li.previous();
270+
271+
QgsMapLayer *ml = QgsMapLayerRegistry::instance()->mapLayer( layerId );
272+
273+
if ( !ml || ( ml->type() != QgsMapLayer::VectorLayer ) )
274+
continue;
275+
276+
// only make labels if the layer is visible
277+
// after scale dep viewing settings are checked
278+
if ( ml->hasScaleBasedVisibility() && ( settings.scale() < ml->minimumScale() || settings.scale() > ml->maximumScale() ) )
279+
continue;
280+
281+
const QgsCoordinateTransform* ct = 0;
282+
QgsRectangle r1 = settings.visibleExtent(), r2;
283+
284+
if ( settings.hasCrsTransformEnabled() )
285+
{
286+
ct = settings.layerTransfrom( ml );
287+
if ( ct )
288+
reprojectToLayerExtent( ct, ml->crs().geographicFlag(), r1, r2 );
289+
}
290+
291+
renderContext.setCoordinateTransform( ct );
292+
renderContext.setExtent( r1 );
293+
294+
ml->drawLabels( renderContext );
295+
}
296+
}
297+
298+
299+
void QgsMapRendererJob::drawNewLabeling( const QgsMapSettings& settings, QgsRenderContext& renderContext, QgsPalLabeling* labelingEngine )
300+
{
301+
if ( labelingEngine && !renderContext.renderingStopped() )
302+
{
303+
// set correct extent
304+
renderContext.setExtent( settings.visibleExtent() );
305+
renderContext.setCoordinateTransform( NULL );
306+
307+
labelingEngine->drawLabeling( renderContext );
308+
labelingEngine->exit();
309+
}
310+
}
311+
312+
void QgsMapRendererJob::updateLayerGeometryCaches()
313+
{
314+
foreach ( QString id, mGeometryCaches.keys() )
315+
{
316+
const QgsGeometryCache& cache = mGeometryCaches[id];
317+
if ( QgsVectorLayer* vl = qobject_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( id ) ) )
318+
* vl->cache() = cache;
319+
}
320+
mGeometryCaches.clear();
321+
}
322+
323+
324+
bool QgsMapRendererJob::needTemporaryImage( QgsMapLayer* ml )
325+
{
326+
if ( mSettings.testFlag( QgsMapSettings::UseAdvancedEffects ) && ml->type() == QgsMapLayer::VectorLayer )
327+
{
328+
QgsVectorLayer* vl = qobject_cast<QgsVectorLayer *>( ml );
329+
if ((( vl->blendMode() != QPainter::CompositionMode_SourceOver )
330+
|| ( vl->featureBlendMode() != QPainter::CompositionMode_SourceOver )
331+
|| ( vl->layerTransparency() != 0 ) ) )
332+
return true;
333+
}
334+
335+
return false;
336+
}
337+
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/***************************************************************************
2+
qgsmaprenderercustompainterjob.h
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSMAPRENDERERCUSTOMPAINTERJOB_H
17+
#define QGSMAPRENDERERCUSTOMPAINTERJOB_H
18+
19+
#include "qgsmaprendererjob.h"
20+
21+
#include <QEventLoop>
22+
23+
/** job implementation that renders everything sequentially using a custom painter.
24+
* The returned image is always invalid (because there is none available).
25+
*/
26+
class CORE_EXPORT QgsMapRendererCustomPainterJob : public QgsMapRendererJob
27+
{
28+
Q_OBJECT
29+
public:
30+
QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter );
31+
~QgsMapRendererCustomPainterJob();
32+
33+
virtual void start();
34+
virtual void cancel();
35+
virtual void waitForFinished();
36+
virtual bool isActive() const;
37+
virtual QgsLabelingResults* takeLabelingResults();
38+
39+
//! @note not available in python bindings
40+
const LayerRenderJobs& jobs() const { return mLayerJobs; }
41+
42+
/**
43+
* Wait for the job to be finished - and keep the thread's event loop running while waiting.
44+
*
45+
* With a call to waitForFinished(), the waiting is done with a synchronization primitive
46+
* and does not involve processing of messages. That may cause issues to code which requires
47+
* some events to be handled in the main thread. Some plugins hooking into the rendering
48+
* pipeline may require this in order to work properly - for example, OpenLayers plugin
49+
* which uses a QWebPage in the main thread.
50+
*
51+
* Ideally the "wait for finished" method should not be used at all. The code triggering
52+
* rendering should not need to actively wait for rendering to finish.
53+
*/
54+
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );
55+
56+
/**
57+
* Render the map synchronously in this thread. The function does not return until the map
58+
* is completely rendered.
59+
*
60+
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
61+
* Users are discouraged to use this method unless they have a strong reason for doing it.
62+
* The synchronous rendering blocks the main thread, making the application unresponsive.
63+
* Also, it is not possible to cancel rendering while it is in progress.
64+
*/
65+
void renderSynchronously();
66+
67+
protected slots:
68+
void futureFinished();
69+
70+
protected:
71+
static void staticRender( QgsMapRendererCustomPainterJob* self ); // function to be used within the thread
72+
73+
// these methods are called within worker thread
74+
void doRender();
75+
76+
private:
77+
QPainter* mPainter;
78+
QFuture<void> mFuture;
79+
QFutureWatcher<void> mFutureWatcher;
80+
QgsRenderContext mLabelingRenderContext;
81+
QgsPalLabeling* mLabelingEngine;
82+
83+
bool mActive;
84+
LayerRenderJobs mLayerJobs;
85+
bool mRenderSynchronously;
86+
};
87+
88+
89+
#endif // QGSMAPRENDERERCUSTOMPAINTERJOB_H

‎src/core/qgsmaprendererjob.cpp

Lines changed: 4 additions & 649 deletions
Large diffs are not rendered by default.

‎src/core/qgsmaprendererjob.h

Lines changed: 0 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -160,155 +160,4 @@ class CORE_EXPORT QgsMapRendererQImageJob : public QgsMapRendererJob
160160
};
161161

162162

163-
class QgsMapRendererCustomPainterJob;
164-
165-
166-
/** job implementation that renders everything sequentially in one thread */
167-
class CORE_EXPORT QgsMapRendererSequentialJob : public QgsMapRendererQImageJob
168-
{
169-
Q_OBJECT
170-
public:
171-
QgsMapRendererSequentialJob( const QgsMapSettings& settings );
172-
~QgsMapRendererSequentialJob();
173-
174-
virtual void start();
175-
virtual void cancel();
176-
virtual void waitForFinished();
177-
virtual bool isActive() const;
178-
179-
virtual QgsLabelingResults* takeLabelingResults();
180-
181-
// from QgsMapRendererJobWithPreview
182-
virtual QImage renderedImage();
183-
184-
public slots:
185-
186-
void internalFinished();
187-
188-
protected:
189-
190-
QgsMapRendererCustomPainterJob* mInternalJob;
191-
QImage mImage;
192-
QPainter* mPainter;
193-
QgsLabelingResults* mLabelingResults;
194-
};
195-
196-
197-
198-
199-
/** job implementation that renders all layers in parallel */
200-
class CORE_EXPORT QgsMapRendererParallelJob : public QgsMapRendererQImageJob
201-
{
202-
Q_OBJECT
203-
public:
204-
QgsMapRendererParallelJob( const QgsMapSettings& settings );
205-
~QgsMapRendererParallelJob();
206-
207-
virtual void start();
208-
virtual void cancel();
209-
virtual void waitForFinished();
210-
virtual bool isActive() const;
211-
212-
virtual QgsLabelingResults* takeLabelingResults();
213-
214-
// from QgsMapRendererJobWithPreview
215-
virtual QImage renderedImage();
216-
217-
protected slots:
218-
//! layers are rendered, labeling is still pending
219-
void renderLayersFinished();
220-
//! all rendering is finished, including labeling
221-
void renderingFinished();
222-
223-
protected:
224-
225-
static void renderLayerStatic( LayerRenderJob& job );
226-
static void renderLabelsStatic( QgsMapRendererParallelJob* self );
227-
228-
protected:
229-
230-
QImage mFinalImage;
231-
232-
enum { Idle, RenderingLayers, RenderingLabels } mStatus;
233-
234-
QFuture<void> mFuture;
235-
QFutureWatcher<void> mFutureWatcher;
236-
237-
LayerRenderJobs mLayerJobs;
238-
239-
QgsPalLabeling* mLabelingEngine;
240-
QgsRenderContext mLabelingRenderContext;
241-
QFuture<void> mLabelingFuture;
242-
QFutureWatcher<void> mLabelingFutureWatcher;
243-
};
244-
245-
246-
#include <QEventLoop>
247-
248-
/** job implementation that renders everything sequentially using a custom painter.
249-
* The returned image is always invalid (because there is none available).
250-
*/
251-
class CORE_EXPORT QgsMapRendererCustomPainterJob : public QgsMapRendererJob
252-
{
253-
Q_OBJECT
254-
public:
255-
QgsMapRendererCustomPainterJob( const QgsMapSettings& settings, QPainter* painter );
256-
~QgsMapRendererCustomPainterJob();
257-
258-
virtual void start();
259-
virtual void cancel();
260-
virtual void waitForFinished();
261-
virtual bool isActive() const;
262-
virtual QgsLabelingResults* takeLabelingResults();
263-
264-
//! @note not available in python bindings
265-
const LayerRenderJobs& jobs() const { return mLayerJobs; }
266-
267-
/**
268-
* Wait for the job to be finished - and keep the thread's event loop running while waiting.
269-
*
270-
* With a call to waitForFinished(), the waiting is done with a synchronization primitive
271-
* and does not involve processing of messages. That may cause issues to code which requires
272-
* some events to be handled in the main thread. Some plugins hooking into the rendering
273-
* pipeline may require this in order to work properly - for example, OpenLayers plugin
274-
* which uses a QWebPage in the main thread.
275-
*
276-
* Ideally the "wait for finished" method should not be used at all. The code triggering
277-
* rendering should not need to actively wait for rendering to finish.
278-
*/
279-
void waitForFinishedWithEventLoop( QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents );
280-
281-
/**
282-
* Render the map synchronously in this thread. The function does not return until the map
283-
* is completely rendered.
284-
*
285-
* This is an alternative to ordinary API (using start() + waiting for finished() signal).
286-
* Users are discouraged to use this method unless they have a strong reason for doing it.
287-
* The synchronous rendering blocks the main thread, making the application unresponsive.
288-
* Also, it is not possible to cancel rendering while it is in progress.
289-
*/
290-
void renderSynchronously();
291-
292-
protected slots:
293-
void futureFinished();
294-
295-
protected:
296-
static void staticRender( QgsMapRendererCustomPainterJob* self ); // function to be used within the thread
297-
298-
// these methods are called within worker thread
299-
void doRender();
300-
301-
private:
302-
QPainter* mPainter;
303-
QFuture<void> mFuture;
304-
QFutureWatcher<void> mFutureWatcher;
305-
QgsRenderContext mLabelingRenderContext;
306-
QgsPalLabeling* mLabelingEngine;
307-
308-
bool mActive;
309-
LayerRenderJobs mLayerJobs;
310-
bool mRenderSynchronously;
311-
};
312-
313-
314163
#endif // QGSMAPRENDERERJOB_H
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
/***************************************************************************
2+
qgsmaprendererparalleljob.cpp
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsmaprendererparalleljob.h"
17+
18+
#include "qgslogger.h"
19+
#include "qgsmaplayerrenderer.h"
20+
#include "qgspallabeling.h"
21+
22+
23+
QgsMapRendererParallelJob::QgsMapRendererParallelJob( const QgsMapSettings& settings )
24+
: QgsMapRendererQImageJob( settings )
25+
, mStatus( Idle )
26+
, mLabelingEngine( 0 )
27+
{
28+
}
29+
30+
QgsMapRendererParallelJob::~QgsMapRendererParallelJob()
31+
{
32+
if ( isActive() )
33+
{
34+
cancel();
35+
}
36+
37+
delete mLabelingEngine;
38+
mLabelingEngine = 0;
39+
}
40+
41+
void QgsMapRendererParallelJob::start()
42+
{
43+
if ( isActive() )
44+
return;
45+
46+
mRenderingStart.start();
47+
48+
mStatus = RenderingLayers;
49+
50+
delete mLabelingEngine;
51+
mLabelingEngine = 0;
52+
53+
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) )
54+
{
55+
mLabelingEngine = new QgsPalLabeling;
56+
mLabelingEngine->loadEngineSettings();
57+
mLabelingEngine->init( mSettings );
58+
}
59+
60+
61+
mLayerJobs = prepareJobs( 0, mLabelingEngine );
62+
63+
QgsDebugMsg( QString( "QThreadPool max thread count is %1" ).arg( QThreadPool::globalInstance()->maxThreadCount() ) );
64+
65+
// start async job
66+
67+
connect( &mFutureWatcher, SIGNAL( finished() ), SLOT( renderLayersFinished() ) );
68+
69+
mFuture = QtConcurrent::map( mLayerJobs, renderLayerStatic );
70+
mFutureWatcher.setFuture( mFuture );
71+
}
72+
73+
void QgsMapRendererParallelJob::cancel()
74+
{
75+
if ( !isActive() )
76+
return;
77+
78+
QgsDebugMsg( QString( "PARALLEL cancel at status %1" ).arg( mStatus ) );
79+
80+
mLabelingRenderContext.setRenderingStopped( true );
81+
for ( LayerRenderJobs::iterator it = mLayerJobs.begin(); it != mLayerJobs.end(); ++it )
82+
{
83+
it->context.setRenderingStopped( true );
84+
}
85+
86+
if ( mStatus == RenderingLayers )
87+
{
88+
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
89+
90+
mFutureWatcher.waitForFinished();
91+
92+
renderLayersFinished();
93+
}
94+
95+
if ( mStatus == RenderingLabels )
96+
{
97+
disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
98+
99+
mLabelingFutureWatcher.waitForFinished();
100+
101+
renderingFinished();
102+
}
103+
104+
Q_ASSERT( mStatus == Idle );
105+
}
106+
107+
void QgsMapRendererParallelJob::waitForFinished()
108+
{
109+
if ( !isActive() )
110+
return;
111+
112+
if ( mStatus == RenderingLayers )
113+
{
114+
disconnect( &mFutureWatcher, SIGNAL( finished() ), this, SLOT( renderLayersFinished() ) );
115+
116+
QTime t;
117+
t.start();
118+
119+
mFutureWatcher.waitForFinished();
120+
121+
QgsDebugMsg( QString( "waitForFinished (1): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
122+
123+
renderLayersFinished();
124+
}
125+
126+
if ( mStatus == RenderingLabels )
127+
{
128+
disconnect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
129+
130+
QTime t;
131+
t.start();
132+
133+
mLabelingFutureWatcher.waitForFinished();
134+
135+
QgsDebugMsg( QString( "waitForFinished (2): %1 ms" ).arg( t.elapsed() / 1000.0 ) );
136+
137+
renderingFinished();
138+
}
139+
140+
Q_ASSERT( mStatus == Idle );
141+
}
142+
143+
bool QgsMapRendererParallelJob::isActive() const
144+
{
145+
return mStatus != Idle;
146+
}
147+
148+
QgsLabelingResults* QgsMapRendererParallelJob::takeLabelingResults()
149+
{
150+
return mLabelingEngine ? mLabelingEngine->takeResults() : 0;
151+
}
152+
153+
QImage QgsMapRendererParallelJob::renderedImage()
154+
{
155+
if ( mStatus == RenderingLayers )
156+
return composeImage( mSettings, mLayerJobs );
157+
else
158+
return mFinalImage; // when rendering labels or idle
159+
}
160+
161+
void QgsMapRendererParallelJob::renderLayersFinished()
162+
{
163+
Q_ASSERT( mStatus == RenderingLayers );
164+
165+
// compose final image
166+
mFinalImage = composeImage( mSettings, mLayerJobs );
167+
168+
cleanupJobs( mLayerJobs );
169+
170+
QgsDebugMsg( "PARALLEL layers finished" );
171+
172+
if ( mSettings.testFlag( QgsMapSettings::DrawLabeling ) && !mLabelingRenderContext.renderingStopped() )
173+
{
174+
mStatus = RenderingLabels;
175+
176+
connect( &mLabelingFutureWatcher, SIGNAL( finished() ), this, SLOT( renderingFinished() ) );
177+
178+
// now start rendering of labeling!
179+
mLabelingFuture = QtConcurrent::run( renderLabelsStatic, this );
180+
mLabelingFutureWatcher.setFuture( mLabelingFuture );
181+
}
182+
else
183+
{
184+
renderingFinished();
185+
}
186+
}
187+
188+
void QgsMapRendererParallelJob::renderingFinished()
189+
{
190+
QgsDebugMsg( "PARALLEL finished" );
191+
192+
mStatus = Idle;
193+
194+
mRenderingTime = mRenderingStart.elapsed();
195+
196+
emit finished();
197+
}
198+
199+
void QgsMapRendererParallelJob::renderLayerStatic( LayerRenderJob& job )
200+
{
201+
if ( job.context.renderingStopped() )
202+
return;
203+
204+
if ( job.cached )
205+
return;
206+
207+
QTime t;
208+
t.start();
209+
QgsDebugMsg( QString( "job %1 start" ).arg(( ulong ) &job, 0, 16 ) );
210+
job.renderer->render();
211+
int tt = t.elapsed();
212+
QgsDebugMsg( QString( "job %1 end [%2 ms]" ).arg(( ulong ) &job, 0, 16 ).arg( tt ) );
213+
Q_UNUSED( tt );
214+
}
215+
216+
217+
void QgsMapRendererParallelJob::renderLabelsStatic( QgsMapRendererParallelJob* self )
218+
{
219+
QPainter painter( &self->mFinalImage );
220+
221+
drawLabeling( self->mSettings, self->mLabelingRenderContext, self->mLabelingEngine, &painter );
222+
223+
painter.end();
224+
}
225+

‎src/core/qgsmaprendererparalleljob.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/***************************************************************************
2+
qgsmaprendererparalleljob.h
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSMAPRENDERERPARALLELJOB_H
17+
#define QGSMAPRENDERERPARALLELJOB_H
18+
19+
#include "qgsmaprendererjob.h"
20+
21+
/** job implementation that renders all layers in parallel */
22+
class CORE_EXPORT QgsMapRendererParallelJob : public QgsMapRendererQImageJob
23+
{
24+
Q_OBJECT
25+
public:
26+
QgsMapRendererParallelJob( const QgsMapSettings& settings );
27+
~QgsMapRendererParallelJob();
28+
29+
virtual void start();
30+
virtual void cancel();
31+
virtual void waitForFinished();
32+
virtual bool isActive() const;
33+
34+
virtual QgsLabelingResults* takeLabelingResults();
35+
36+
// from QgsMapRendererJobWithPreview
37+
virtual QImage renderedImage();
38+
39+
protected slots:
40+
//! layers are rendered, labeling is still pending
41+
void renderLayersFinished();
42+
//! all rendering is finished, including labeling
43+
void renderingFinished();
44+
45+
protected:
46+
47+
static void renderLayerStatic( LayerRenderJob& job );
48+
static void renderLabelsStatic( QgsMapRendererParallelJob* self );
49+
50+
protected:
51+
52+
QImage mFinalImage;
53+
54+
enum { Idle, RenderingLayers, RenderingLabels } mStatus;
55+
56+
QFuture<void> mFuture;
57+
QFutureWatcher<void> mFutureWatcher;
58+
59+
LayerRenderJobs mLayerJobs;
60+
61+
QgsPalLabeling* mLabelingEngine;
62+
QgsRenderContext mLabelingRenderContext;
63+
QFuture<void> mLabelingFuture;
64+
QFutureWatcher<void> mLabelingFutureWatcher;
65+
};
66+
67+
68+
#endif // QGSMAPRENDERERPARALLELJOB_H
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/***************************************************************************
2+
qgsmaprenderersequentialjob.cpp
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#include "qgsmaprenderersequentialjob.h"
17+
18+
#include "qgslogger.h"
19+
#include "qgsmaprenderercustompainterjob.h"
20+
#include "qgspallabeling.h"
21+
22+
23+
QgsMapRendererSequentialJob::QgsMapRendererSequentialJob( const QgsMapSettings& settings )
24+
: QgsMapRendererQImageJob( settings )
25+
, mInternalJob( 0 )
26+
, mPainter( 0 )
27+
, mLabelingResults( 0 )
28+
{
29+
QgsDebugMsg( "SEQUENTIAL construct" );
30+
31+
mImage = QImage( mSettings.outputSize(), mSettings.outputImageFormat() );
32+
}
33+
34+
QgsMapRendererSequentialJob::~QgsMapRendererSequentialJob()
35+
{
36+
QgsDebugMsg( "SEQUENTIAL destruct" );
37+
if ( isActive() )
38+
{
39+
// still running!
40+
QgsDebugMsg( "SEQUENTIAL destruct -- still running! (cancelling)" );
41+
cancel();
42+
}
43+
44+
Q_ASSERT( mInternalJob == 0 && mPainter == 0 );
45+
46+
delete mLabelingResults;
47+
mLabelingResults = 0;
48+
}
49+
50+
51+
void QgsMapRendererSequentialJob::start()
52+
{
53+
if ( isActive() )
54+
return; // do nothing if we are already running
55+
56+
mRenderingStart.start();
57+
58+
mErrors.clear();
59+
60+
QgsDebugMsg( "SEQUENTIAL START" );
61+
62+
Q_ASSERT( mInternalJob == 0 && mPainter == 0 );
63+
64+
mPainter = new QPainter( &mImage );
65+
66+
mInternalJob = new QgsMapRendererCustomPainterJob( mSettings, mPainter );
67+
mInternalJob->setCache( mCache );
68+
69+
connect( mInternalJob, SIGNAL( finished() ), SLOT( internalFinished() ) );
70+
71+
mInternalJob->start();
72+
}
73+
74+
75+
void QgsMapRendererSequentialJob::cancel()
76+
{
77+
if ( !isActive() )
78+
return;
79+
80+
QgsDebugMsg( "sequential - cancel internal" );
81+
mInternalJob->cancel();
82+
83+
Q_ASSERT( mInternalJob == 0 && mPainter == 0 );
84+
}
85+
86+
void QgsMapRendererSequentialJob::waitForFinished()
87+
{
88+
if ( !isActive() )
89+
return;
90+
91+
mInternalJob->waitForFinished();
92+
}
93+
94+
bool QgsMapRendererSequentialJob::isActive() const
95+
{
96+
return mInternalJob != 0;
97+
}
98+
99+
QgsLabelingResults* QgsMapRendererSequentialJob::takeLabelingResults()
100+
{
101+
QgsLabelingResults* tmp = mLabelingResults;
102+
mLabelingResults = 0;
103+
return tmp;
104+
}
105+
106+
107+
QImage QgsMapRendererSequentialJob::renderedImage()
108+
{
109+
if ( isActive() && mCache )
110+
// this will allow immediate display of cached layers and at the same time updates of the layer being rendered
111+
return composeImage( mSettings, mInternalJob->jobs() );
112+
else
113+
return mImage;
114+
}
115+
116+
117+
void QgsMapRendererSequentialJob::internalFinished()
118+
{
119+
QgsDebugMsg( "SEQUENTIAL finished" );
120+
121+
mPainter->end();
122+
delete mPainter;
123+
mPainter = 0;
124+
125+
mLabelingResults = mInternalJob->takeLabelingResults();
126+
127+
mErrors = mInternalJob->errors();
128+
129+
// now we are in a slot called from mInternalJob - do not delete it immediately
130+
// so the class is still valid when the execution returns to the class
131+
mInternalJob->deleteLater();
132+
mInternalJob = 0;
133+
134+
mRenderingTime = mRenderingStart.elapsed();
135+
136+
emit finished();
137+
}
138+
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/***************************************************************************
2+
qgsmaprenderersequentialjob.h
3+
--------------------------------------
4+
Date : December 2013
5+
Copyright : (C) 2013 by Martin Dobias
6+
Email : wonder dot sk at gmail dot com
7+
***************************************************************************
8+
* *
9+
* This program is free software; you can redistribute it and/or modify *
10+
* it under the terms of the GNU General Public License as published by *
11+
* the Free Software Foundation; either version 2 of the License, or *
12+
* (at your option) any later version. *
13+
* *
14+
***************************************************************************/
15+
16+
#ifndef QGSMAPRENDERERSEQUENTIALJOB_H
17+
#define QGSMAPRENDERERSEQUENTIALJOB_H
18+
19+
#include "qgsmaprendererjob.h"
20+
21+
class QgsMapRendererCustomPainterJob;
22+
23+
/** job implementation that renders everything sequentially in one thread */
24+
class CORE_EXPORT QgsMapRendererSequentialJob : public QgsMapRendererQImageJob
25+
{
26+
Q_OBJECT
27+
public:
28+
QgsMapRendererSequentialJob( const QgsMapSettings& settings );
29+
~QgsMapRendererSequentialJob();
30+
31+
virtual void start();
32+
virtual void cancel();
33+
virtual void waitForFinished();
34+
virtual bool isActive() const;
35+
36+
virtual QgsLabelingResults* takeLabelingResults();
37+
38+
// from QgsMapRendererJobWithPreview
39+
virtual QImage renderedImage();
40+
41+
public slots:
42+
43+
void internalFinished();
44+
45+
protected:
46+
47+
QgsMapRendererCustomPainterJob* mInternalJob;
48+
QImage mImage;
49+
QPainter* mPainter;
50+
QgsLabelingResults* mLabelingResults;
51+
};
52+
53+
54+
#endif // QGSMAPRENDERERSEQUENTIALJOB_H

‎src/core/qgsrenderchecker.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "qgsrenderchecker.h"
1717

1818
#include "qgis.h"
19-
#include "qgsmaprendererjob.h"
19+
#include "qgsmaprenderersequentialjob.h"
2020

2121
#include <QColor>
2222
#include <QPainter>

‎src/gui/qgsmapcanvas.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ email : sherman at mrcc.com
5252
#include "qgsmapoverviewcanvas.h"
5353
#include "qgsmaprenderer.h"
5454
#include "qgsmaprenderercache.h"
55-
#include "qgsmaprendererjob.h"
55+
#include "qgsmaprenderercustompainterjob.h"
56+
#include "qgsmaprendererparalleljob.h"
57+
#include "qgsmaprenderersequentialjob.h"
5658
#include "qgsmessagelog.h"
5759
#include "qgsmessageviewer.h"
5860
#include "qgspallabeling.h"

‎src/gui/qgsmapoverviewcanvas.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#include "qgsmapcanvas.h"
2020
#include "qgsmapoverviewcanvas.h"
21-
#include "qgsmaprendererjob.h"
21+
#include "qgsmaprenderersequentialjob.h"
2222
#include "qgsmaptopixel.h"
2323

2424
#include <QPainter>

‎tests/bench/qgsbench.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@
4040
#include "qgsbench.h"
4141
#include "qgslogger.h"
4242
#include "qgsmaplayerregistry.h"
43-
#include "qgsmaprendererjob.h"
43+
#include "qgsmaprendererparalleljob.h"
44+
#include "qgsmaprenderersequentialjob.h"
4445
#include "qgsproject.h"
4546

4647
const char *pre[] = { "user", "sys", "total", "wall" };

0 commit comments

Comments
 (0)
Please sign in to comment.