@@ -115,9 +115,16 @@ QgsComposerMap::~QgsComposerMap()
115
115
{
116
116
delete mOverviewStack ;
117
117
delete mGridStack ;
118
+
119
+ if ( mPainterJob )
120
+ {
121
+ disconnect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
122
+ mPainterJob ->cancel ();
123
+ mPainter ->end ();
124
+ }
118
125
}
119
126
120
- /* This function is called by paint() and cache() to render the map. It does not override any functions
127
+ /* This function is called by paint() to render the map. It does not override any functions
121
128
from QGraphicsItem. */
122
129
void QgsComposerMap::draw ( QPainter *painter, const QgsRectangle &extent, QSizeF size, double dpi, double *forceWidthScale )
123
130
{
@@ -206,12 +213,28 @@ void QgsComposerMap::cache()
206
213
return ;
207
214
}
208
215
209
- if ( mDrawing )
216
+ if ( mPainterJob )
210
217
{
211
- return ;
218
+ disconnect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
219
+ QgsMapRendererCustomPainterJob *oldJob = mPainterJob .release ();
220
+ QPainter *oldPainter = mPainter .release ();
221
+ QImage *oldImage = mCacheRenderingImage .release ();
222
+ connect ( oldJob, &QgsMapRendererCustomPainterJob::finished, this , [oldPainter, oldJob, oldImage]
223
+ {
224
+ oldJob->deleteLater ();
225
+ delete oldPainter;
226
+ delete oldImage;
227
+ } );
228
+ oldJob->cancelWithoutBlocking ();
229
+ }
230
+ else
231
+ {
232
+ mCacheRenderingImage .reset ( nullptr );
212
233
}
213
234
214
- mDrawing = true ;
235
+ Q_ASSERT ( !mPainterJob );
236
+ Q_ASSERT ( !mPainter );
237
+ Q_ASSERT ( !mCacheRenderingImage );
215
238
216
239
double horizontalVScaleFactor = horizontalViewScaleFactor ();
217
240
if ( horizontalVScaleFactor < 0 )
@@ -242,38 +265,51 @@ void QgsComposerMap::cache()
242
265
}
243
266
}
244
267
245
- mCacheImage = QImage ( w, h, QImage::Format_ARGB32 );
268
+ if ( w <= 0 || h <= 0 )
269
+ return ;
270
+
271
+ mCacheRenderingImage .reset ( new QImage ( w, h, QImage::Format_ARGB32 ) );
246
272
247
273
// set DPI of the image
248
- mCacheImage . setDotsPerMeterX ( 1000 * w / widthMM );
249
- mCacheImage . setDotsPerMeterY ( 1000 * h / heightMM );
274
+ mCacheRenderingImage -> setDotsPerMeterX ( 1000 * w / widthMM );
275
+ mCacheRenderingImage -> setDotsPerMeterY ( 1000 * h / heightMM );
250
276
251
277
if ( hasBackground () )
252
278
{
253
279
// Initially fill image with specified background color. This ensures that layers with blend modes will
254
280
// preview correctly
255
- mCacheImage . fill ( backgroundColor ().rgba () );
281
+ mCacheRenderingImage -> fill ( backgroundColor ().rgba () );
256
282
}
257
283
else
258
284
{
259
285
// no background, but start with empty fill to avoid artifacts
260
- mCacheImage . fill ( QColor ( 255 , 255 , 255 , 0 ).rgba () );
286
+ mCacheRenderingImage -> fill ( QColor ( 255 , 255 , 255 , 0 ).rgba () );
261
287
}
262
288
263
- QPainter p ( &mCacheImage );
289
+ mPainter .reset ( new QPainter ( mCacheRenderingImage .get () ) );
290
+ QgsMapSettings settings ( mapSettings ( ext, QSizeF ( w, h ), mCacheRenderingImage ->logicalDpiX () ) );
291
+ mPainterJob .reset ( new QgsMapRendererCustomPainterJob ( settings, mPainter .get () ) );
292
+ connect ( mPainterJob .get (), &QgsMapRendererCustomPainterJob::finished, this , &QgsComposerMap::painterJobFinished );
293
+ mPainterJob ->start ();
294
+ }
264
295
265
- draw ( &p, ext, QSizeF ( w, h ), mCacheImage .logicalDpiX () );
266
- p.end ();
296
+ void QgsComposerMap::painterJobFinished ()
297
+ {
298
+ mPainter ->end ();
299
+ mPainterJob .reset ( nullptr );
300
+ mPainter .reset ( nullptr );
267
301
mCacheUpdated = true ;
268
-
269
- mDrawing = false ;
302
+ mCacheFinalImage = std::move ( mCacheRenderingImage );
303
+ mLastRenderedImageOffsetX = 0 ;
304
+ mLastRenderedImageOffsetY = 0 ;
305
+ updateItem ();
270
306
}
271
307
272
308
void QgsComposerMap::paint ( QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *pWidget )
273
309
{
274
310
Q_UNUSED ( pWidget );
275
311
276
- if ( !mComposition || !painter )
312
+ if ( !mComposition || !painter || !painter-> device () )
277
313
{
278
314
return ;
279
315
}
@@ -283,6 +319,9 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
283
319
}
284
320
285
321
QRectF thisPaintRect = QRectF ( 0 , 0 , QGraphicsRectItem::rect ().width (), QGraphicsRectItem::rect ().height () );
322
+ if ( thisPaintRect.width () == 0 || thisPaintRect.height () == 0 )
323
+ return ;
324
+
286
325
painter->save ();
287
326
painter->setClipRect ( thisPaintRect );
288
327
@@ -297,22 +336,40 @@ void QgsComposerMap::paint( QPainter *painter, const QStyleOptionGraphicsItem *,
297
336
}
298
337
else if ( mComposition ->plotStyle () == QgsComposition::Preview )
299
338
{
300
- if ( mCacheImage .isNull () )
301
- cache ();
302
-
303
- // Background color is already included in cached image, so no need to draw
339
+ if ( !mCacheFinalImage || mCacheFinalImage ->isNull () )
340
+ {
341
+ // No initial render available - so draw some preview text alerting user
342
+ drawBackground ( painter );
343
+ painter->setBrush ( QBrush ( QColor ( 125 , 125 , 125 , 125 ) ) );
344
+ painter->drawRect ( thisPaintRect );
345
+ painter->setBrush ( Qt::NoBrush );
346
+ QFont messageFont;
347
+ messageFont.setPointSize ( 12 );
348
+ painter->setFont ( messageFont );
349
+ painter->setPen ( QColor ( 255 , 255 , 255 , 255 ) );
350
+ painter->drawText ( thisPaintRect, Qt::AlignCenter | Qt::AlignHCenter, tr ( " Rendering map" ) );
351
+ if ( !mPainterJob )
352
+ {
353
+ // this is the map's very first paint - trigger a cache update
354
+ cache ();
355
+ }
356
+ }
357
+ else
358
+ {
359
+ // Background color is already included in cached image, so no need to draw
304
360
305
- double imagePixelWidth = mCacheImage . width (); // how many pixels of the image are for the map extent?
306
- double scale = rect ().width () / imagePixelWidth;
361
+ double imagePixelWidth = mCacheFinalImage -> width (); // how many pixels of the image are for the map extent?
362
+ double scale = rect ().width () / imagePixelWidth;
307
363
308
- painter->save ();
364
+ painter->save ();
309
365
310
- painter->translate ( mXOffset , mYOffset );
311
- painter->scale ( scale, scale );
312
- painter->drawImage ( 0 , 0 , mCacheImage );
366
+ painter->translate ( mLastRenderedImageOffsetX + mXOffset , mLastRenderedImageOffsetY + mYOffset );
367
+ painter->scale ( scale, scale );
368
+ painter->drawImage ( 0 , 0 , * mCacheFinalImage );
313
369
314
- // restore rotation
315
- painter->restore ();
370
+ // restore rotation
371
+ painter->restore ();
372
+ }
316
373
}
317
374
else if ( mComposition ->plotStyle () == QgsComposition::Print ||
318
375
mComposition ->plotStyle () == QgsComposition::Postscript )
@@ -565,6 +622,8 @@ void QgsComposerMap::resize( double dx, double dy )
565
622
566
623
void QgsComposerMap::moveContent ( double dx, double dy )
567
624
{
625
+ mLastRenderedImageOffsetX -= dx;
626
+ mLastRenderedImageOffsetY -= dy;
568
627
if ( !mDrawing )
569
628
{
570
629
transformShift ( dx, dy );
@@ -673,7 +732,7 @@ void QgsComposerMap::setSceneRect( const QRectF &rectangle )
673
732
mCacheUpdated = false ;
674
733
675
734
updateBoundingRect ();
676
- update ();
735
+ updateItem ();
677
736
emit itemChanged ();
678
737
emit extentChanged ();
679
738
}
0 commit comments