Skip to content

Commit

Permalink
Reporting of rendering errors, safer isActive() for custom painter job
Browse files Browse the repository at this point in the history
  • Loading branch information
wonder-sk committed Nov 26, 2013
1 parent 9a4f326 commit 879f051
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 43 deletions.
20 changes: 8 additions & 12 deletions src/core/qgsmaplayerrenderer.h
Original file line number Original file line Diff line number Diff line change
@@ -1,8 +1,7 @@
#ifndef QGSMAPLAYERRENDERER_H #ifndef QGSMAPLAYERRENDERER_H
#define QGSMAPLAYERRENDERER_H #define QGSMAPLAYERRENDERER_H


#include <QList> #include <QStringList>
#include <QString>


/** /**
* Base class for utility classes that encapsulate information necessary * Base class for utility classes that encapsulate information necessary
Expand All @@ -27,24 +26,21 @@
class QgsMapLayerRenderer class QgsMapLayerRenderer
{ {
public: public:
QgsMapLayerRenderer( const QString& layerID ) : mLayerID( layerID ) {}
virtual ~QgsMapLayerRenderer() {} virtual ~QgsMapLayerRenderer() {}


//! Do the rendering (based on data stored in the class) //! Do the rendering (based on data stored in the class)
virtual bool render() = 0; virtual bool render() = 0;


//! Container for errors (@todo instead of simple message could have error codes + custom data)
struct Error
{
QString message;
};

typedef QList<Error> ErrorList;

//! Return list of errors (problems) that happened during the rendering //! Return list of errors (problems) that happened during the rendering
ErrorList errors() const { return mErrors; } QStringList errors() const { return mErrors; }

//! Get access to the ID of the layer rendered by this class
QString layerID() const { return mLayerID; }


protected: protected:
ErrorList mErrors; QStringList mErrors;
QString mLayerID;
}; };


#endif // QGSMAPLAYERRENDERER_H #endif // QGSMAPLAYERRENDERER_H
59 changes: 35 additions & 24 deletions src/core/qgsmaprendererjob.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ QgsMapRendererJob::QgsMapRendererJob( const QgsMapSettings& settings )
{ {
} }


QgsMapRendererJob::Errors QgsMapRendererJob::errors() const
{
return mErrors;
}



QgsMapRendererQImageJob::QgsMapRendererQImageJob( const QgsMapSettings& settings ) QgsMapRendererQImageJob::QgsMapRendererQImageJob( const QgsMapSettings& settings )
: QgsMapRendererJob( settings ) : QgsMapRendererJob( settings )
Expand Down Expand Up @@ -59,6 +64,8 @@ void QgsMapRendererSequentialJob::start()
if ( isActive() ) if ( isActive() )
return; // do nothing if we are already running return; // do nothing if we are already running


mErrors.clear();

qDebug("SEQUENTIAL START"); qDebug("SEQUENTIAL START");
qDebug("%d,%d", mSettings.outputSize().width(), mSettings.outputSize().height()); qDebug("%d,%d", mSettings.outputSize().width(), mSettings.outputSize().height());


Expand Down Expand Up @@ -122,6 +129,8 @@ void QgsMapRendererSequentialJob::internalFinished()


mLabelingResults = mInternalJob->takeLabelingResults(); mLabelingResults = mInternalJob->takeLabelingResults();


mErrors = mInternalJob->errors();

delete mInternalJob; delete mInternalJob;
mInternalJob = 0; mInternalJob = 0;


Expand All @@ -137,6 +146,7 @@ QgsMapRendererCustomPainterJob::QgsMapRendererCustomPainterJob(const QgsMapSetti
: QgsMapRendererJob( settings ) : QgsMapRendererJob( settings )
, mPainter(painter) , mPainter(painter)
, mLabelingEngine( 0 ) , mLabelingEngine( 0 )
, mActive( false )
{ {
qDebug("QPAINTER construct"); qDebug("QPAINTER construct");
} }
Expand All @@ -153,6 +163,13 @@ QgsMapRendererCustomPainterJob::~QgsMapRendererCustomPainterJob()


void QgsMapRendererCustomPainterJob::start() void QgsMapRendererCustomPainterJob::start()
{ {
if ( isActive() )
return;

mActive = true;

mErrors.clear();

qDebug("QPAINTER run!"); qDebug("QPAINTER run!");


QgsDebugMsg( "Preparing list of layer jobs for rendering" ); QgsDebugMsg( "Preparing list of layer jobs for rendering" );
Expand Down Expand Up @@ -200,9 +217,12 @@ void QgsMapRendererCustomPainterJob::start()


void QgsMapRendererCustomPainterJob::cancel() void QgsMapRendererCustomPainterJob::cancel()
{ {
// TODO: custom flag indicating that some rendering has started? if ( !isActive() )
//if (mFuture.isRunning())
{ {
qDebug("QPAINTER not running!");
return;
}

qDebug("QPAINTER cancelling"); qDebug("QPAINTER cancelling");
disconnect(&mFutureWatcher, SIGNAL(finished()), this, SLOT(futureFinished())); disconnect(&mFutureWatcher, SIGNAL(finished()), this, SLOT(futureFinished()));


Expand All @@ -222,14 +242,11 @@ void QgsMapRendererCustomPainterJob::cancel()
futureFinished(); futureFinished();


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


void QgsMapRendererCustomPainterJob::waitForFinished() void QgsMapRendererCustomPainterJob::waitForFinished()
{ {
if (!mFuture.isRunning()) if ( !isActive() )
return; return;


disconnect(&mFutureWatcher, SIGNAL(finished()), this, SLOT(futureFinished())); disconnect(&mFutureWatcher, SIGNAL(finished()), this, SLOT(futureFinished()));
Expand All @@ -246,7 +263,7 @@ void QgsMapRendererCustomPainterJob::waitForFinished()


bool QgsMapRendererCustomPainterJob::isActive() const bool QgsMapRendererCustomPainterJob::isActive() const
{ {
return mFutureWatcher.isRunning(); return mActive;
} }




Expand All @@ -258,6 +275,7 @@ QgsLabelingResults* QgsMapRendererCustomPainterJob::takeLabelingResults()


void QgsMapRendererCustomPainterJob::futureFinished() void QgsMapRendererCustomPainterJob::futureFinished()
{ {
mActive = false;
qDebug("QPAINTER futureFinished"); qDebug("QPAINTER futureFinished");
emit finished(); emit finished();
} }
Expand Down Expand Up @@ -473,7 +491,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin


if ( !ml ) if ( !ml )
{ {
QgsDebugMsg( "Layer not found in registry!" ); mErrors.append( Error( layerId, "Layer not found in registry." ) );
continue; continue;
} }


Expand Down Expand Up @@ -502,8 +520,11 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin
split = reprojectToLayerExtent( ct, ml->crs().geographicFlag(), r1, r2 ); split = reprojectToLayerExtent( ct, ml->crs().geographicFlag(), r1, r2 );
QgsDebugMsg( " extent 1: " + r1.toString() ); QgsDebugMsg( " extent 1: " + r1.toString() );
QgsDebugMsg( " extent 2: " + r2.toString() ); QgsDebugMsg( " extent 2: " + r2.toString() );
if ( !r1.isFinite() || !r2.isFinite() ) //there was a problem transforming the extent. Skip the layer if ( !r1.isFinite() || !r2.isFinite() )
{
mErrors.append( Error( layerId, "There was a problem transforming layer's' extent. Layer skipped." ) );
continue; continue;
}
} }


// Flattened image for drawing when a blending mode is set // Flattened image for drawing when a blending mode is set
Expand All @@ -518,8 +539,7 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin
mSettings.outputSize().height(), QImage::Format_ARGB32 ); mSettings.outputSize().height(), QImage::Format_ARGB32 );
if ( mypFlattenedImage->isNull() ) if ( mypFlattenedImage->isNull() )
{ {
QgsDebugMsg( "insufficient memory for image " + QString::number( mSettings.outputSize().width() ) + "x" + QString::number( mSettings.outputSize().height() ) ); mErrors.append( Error( layerId, "Insufficient memory for image " + QString::number( mSettings.outputSize().width() ) + "x" + QString::number( mSettings.outputSize().height() ) ) );
// TODO: add to the list of errors!
delete mypFlattenedImage; delete mypFlattenedImage;
continue; continue;
} }
Expand Down Expand Up @@ -549,22 +569,10 @@ LayerRenderJobs QgsMapRendererJob::prepareJobs( QPainter* painter, QgsPalLabelin


/* /*
// TODO: split extent // TODO: split extent
if ( !ml->draw( mRenderContext ) )
{
// TODO emit drawError( ml );
}
else
{
QgsDebugMsg( "Layer rendered without issues" );
}
if ( split ) if ( split )
{ {
mRenderContext.setExtent( r2 ); mRenderContext.setExtent( r2 );
if ( !ml->draw( mRenderContext ) ) ml->draw( mRenderContext );
{
// TODO emit drawError( ml );
}
}*/ }*/


} // while (li.hasPrevious()) } // while (li.hasPrevious())
Expand All @@ -587,6 +595,9 @@ void QgsMapRendererJob::cleanupJobs( LayerRenderJobs& jobs )
job.img = 0; job.img = 0;
} }


foreach ( QString message, job.renderer->errors() )
mErrors.append( Error( job.renderer->layerID(), message ) );

delete job.renderer; delete job.renderer;
job.renderer = 0; job.renderer = 0;
} }
Expand Down
17 changes: 16 additions & 1 deletion src/core/qgsmaprendererjob.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -55,6 +55,19 @@ class QgsMapRendererJob : public QObject
//! Get pointer to internal labeling engine (in order to get access to the results) //! Get pointer to internal labeling engine (in order to get access to the results)
virtual QgsLabelingResults* takeLabelingResults() = 0; virtual QgsLabelingResults* takeLabelingResults() = 0;


struct Error
{
Error( const QString& lid, const QString& msg ) : layerID( lid ), message( msg ) {}

QString layerID;
QString message;
};

typedef QList<Error> Errors;

//! List of errors that happened during the rendering job - available when the rendering has been finished
Errors errors() const;

signals: signals:


//! emitted when asynchronous rendering is finished (or canceled). //! emitted when asynchronous rendering is finished (or canceled).
Expand All @@ -72,12 +85,13 @@ class QgsMapRendererJob : public QObject


LayerRenderJobs prepareJobs( QPainter* painter, QgsPalLabeling* labelingEngine ); LayerRenderJobs prepareJobs( QPainter* painter, QgsPalLabeling* labelingEngine );


static void cleanupJobs( LayerRenderJobs& jobs ); void cleanupJobs( LayerRenderJobs& jobs );


bool needTemporaryImage( QgsMapLayer* ml ); bool needTemporaryImage( QgsMapLayer* ml );




QgsMapSettings mSettings; QgsMapSettings mSettings;
Errors mErrors;
}; };




Expand Down Expand Up @@ -203,6 +217,7 @@ protected slots:
QgsRenderContext mRenderContext; // used just for labeling! QgsRenderContext mRenderContext; // used just for labeling!
QgsPalLabeling* mLabelingEngine; QgsPalLabeling* mLabelingEngine;


bool mActive;
LayerRenderJobs mLayerJobs; LayerRenderJobs mLayerJobs;
}; };


Expand Down
9 changes: 6 additions & 3 deletions src/core/qgsvectorlayerrenderer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@




QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRenderContext& context ) QgsVectorLayerRenderer::QgsVectorLayerRenderer( QgsVectorLayer* layer, QgsRenderContext& context )
: mContext( context ) : QgsMapLayerRenderer( layer->id() )
, mContext( context )
, mFields( layer->pendingFields() ) , mFields( layer->pendingFields() )
, mLayerID( layer->id() )
, mRendererV2( 0 ) , mRendererV2( 0 )
, mCache( 0 ) , mCache( 0 )
, mLabeling( false ) , mLabeling( false )
, mDiagrams( false ) , mDiagrams( false )
, mLayerTransparency( 0 ) , mLayerTransparency( 0 )
{ {
mRendererV2 = layer->rendererV2()->clone(); mRendererV2 = layer->rendererV2() ? layer->rendererV2()->clone() : 0;
mSelectedFeatureIds = layer->selectedFeaturesIds(); mSelectedFeatureIds = layer->selectedFeaturesIds();


mDrawVertexMarkers = ( layer->editBuffer() != 0 ); mDrawVertexMarkers = ( layer->editBuffer() != 0 );
Expand Down Expand Up @@ -101,7 +101,10 @@ bool QgsVectorLayerRenderer::render()
return true; return true;


if ( !mRendererV2 ) if ( !mRendererV2 )
{
mErrors.append( "No renderer for drawing." );
return false; return false;
}


// Per feature blending mode // Per feature blending mode
if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver ) if ( mContext.useAdvancedEffects() && mFeatureBlendMode != QPainter::CompositionMode_SourceOver )
Expand Down
2 changes: 0 additions & 2 deletions src/core/qgsvectorlayerrenderer.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@ class QgsVectorLayerRenderer : public QgsMapLayerRenderer


QgsFields mFields; QgsFields mFields;


QString mLayerID;

QgsFeatureIds mSelectedFeatureIds; QgsFeatureIds mSelectedFeatureIds;


QgsFeatureIterator mFit; QgsFeatureIterator mFit;
Expand Down
3 changes: 2 additions & 1 deletion src/core/raster/qgsrasterlayerrenderer.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@




QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext ) QgsRasterLayerRenderer::QgsRasterLayerRenderer( QgsRasterLayer* layer, QgsRenderContext& rendererContext )
: mRasterViewPort( 0 ) : QgsMapLayerRenderer( layer->id() )
, mRasterViewPort( 0 )
, mPipe( 0 ) , mPipe( 0 )
{ {


Expand Down
6 changes: 6 additions & 0 deletions src/gui/qgsmapcanvas.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -496,6 +496,12 @@ void QgsMapCanvas::rendererJobFinished()


mDirty = false; mDirty = false;


// TODO: would be better to show the errors in message bar
foreach ( const QgsMapRendererJob::Error& error, mJob->errors() )
{
QgsMessageLog::logMessage( error.layerID + " :: " + error.message, tr( "Rendering" ) );
}

if ( !mJobCancelled ) if ( !mJobCancelled )
{ {
QImage img = mJob->renderedImage(); QImage img = mJob->renderedImage();
Expand Down
31 changes: 31 additions & 0 deletions tests/src/core/testmaprendererjob.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class TestQgsMapRendererJob : public QObject
void testStartWhileRunning(); void testStartWhileRunning();
void testDestructWhileRunning(); void testDestructWhileRunning();


void testErrors();

private: private:
QStringList mLayerIds; QStringList mLayerIds;
}; };
Expand Down Expand Up @@ -202,6 +204,35 @@ void TestQgsMapRendererJob::testDestructWhileRunning()
jobP.start(); jobP.start();
} }


void TestQgsMapRendererJob::testErrors()
{
QgsVectorLayer* l = new QgsVectorLayer( "/data/gis/sas/trans-trail-l.dbf", "test", "ogr" );
QVERIFY( l->isValid() );
QgsMapLayerRegistry::instance()->addMapLayer( l );
QgsMapSettings settings( _mapSettings( QStringList( l->id() ) ) );

l->setRendererV2( 0 ); // this has to produce an error

QgsMapRendererSequentialJob job( settings );
job.start();
job.waitForFinished();

QCOMPARE( job.errors().count(), 1 );
QCOMPARE( job.errors()[0].layerID, l->id() );

QgsMapLayerRegistry::instance()->removeMapLayer( l->id() );

QString fakeLayerID = "non-existing layer ID";
QgsMapSettings settings2( _mapSettings( QStringList( fakeLayerID ) ) );

QgsMapRendererSequentialJob job2( settings2 );
job2.start();
job2.waitForFinished();

QCOMPARE( job2.errors().count(), 1 );
QCOMPARE( job2.errors()[0].layerID, fakeLayerID );
}



QTEST_MAIN( TestQgsMapRendererJob ) QTEST_MAIN( TestQgsMapRendererJob )
#include "moc_testmaprendererjob.cxx" #include "moc_testmaprendererjob.cxx"

0 comments on commit 879f051

Please sign in to comment.