Skip to content
Permalink
Browse files
Add handling of dependent layers to task manager
If a task has dependent layers which are about to be removed,
the task will automatically be cancelled
  • Loading branch information
nyalldawson committed Dec 5, 2016
1 parent eb34079 commit 55e9d326711f77b4572e67ae0fd3e2b2d130be83
Showing with 111 additions and 3 deletions.
  1. +16 −0 python/core/qgstaskmanager.sip
  2. +40 −1 src/core/qgstaskmanager.cpp
  3. +18 −0 src/core/qgstaskmanager.h
  4. +37 −2 tests/src/core/testqgstaskmanager.cpp
@@ -219,6 +219,22 @@ class QgsTaskManager : QObject
//! Will return true if the specified task has circular dependencies
bool hasCircularDependencies( long taskId ) const;

/** Sets a list of layers on which as task is dependent. The task will automatically
* be cancelled if any of these layers are above to be removed.
* @param taskId task ID
* @param layerIds list of layer IDs
* @see dependentLayers()
*/
void setDependentLayers( long taskId, const QStringList& layerIds );

/** Returns a list of layers on which as task is dependent. The task will automatically
* be cancelled if any of these layers are above to be removed.
* @param taskId task ID
* @returns list of layer IDs
* @see setDependentLayers()
*/
QStringList dependentLayers( long taskId ) const;

signals:

//! Will be emitted when a task reports a progress change
@@ -16,6 +16,7 @@
***************************************************************************/

#include "qgstaskmanager.h"
#include "qgsmaplayerregistry.h"
#include <QtConcurrentRun>


@@ -108,7 +109,10 @@ QgsTaskManager *QgsTaskManager::instance()
QgsTaskManager::QgsTaskManager( QObject* parent )
: QObject( parent )
, mNextTaskId( 0 )
{}
{
connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ),
this, SLOT( layersWillBeRemoved( QStringList ) ) );
}

QgsTaskManager::~QgsTaskManager()
{
@@ -276,6 +280,16 @@ bool QgsTaskManager::hasCircularDependencies( long taskId ) const
return !resolveDependencies( taskId, taskId, d );
}

void QgsTaskManager::setDependentLayers( long taskId, const QStringList& layerIds )
{
mLayerDependencies.insert( taskId, layerIds );
}

QStringList QgsTaskManager::dependentLayers( long taskId ) const
{
return mLayerDependencies.value( taskId, QStringList() );
}

void QgsTaskManager::taskProgressChanged( double progress )
{
QgsTask* task = qobject_cast< QgsTask* >( sender() );
@@ -307,6 +321,31 @@ void QgsTaskManager::taskStatusChanged( int status )
processQueue();
}

void QgsTaskManager::layersWillBeRemoved( const QStringList& layerIds )
{
// scan through layers to be removed
Q_FOREACH ( const QString& layerId, layerIds )
{
// scan through tasks with layer dependencies
for ( QMap< long, QStringList >::const_iterator it = mLayerDependencies.constBegin();
it != mLayerDependencies.constEnd(); ++it )
{
if ( !it.value().contains( layerId ) )
{
//task not dependent on this layer
continue;
}

QgsTask* dependentTask = task( it.key() );
if ( dependentTask && ( dependentTask->status() != QgsTask::Complete || dependentTask->status() != QgsTask::Terminated ) )
{
// incomplete task is dependent on this layer!
dependentTask->cancel();
}
}
}
}

bool QgsTaskManager::cleanupAndDeleteTask( QgsTask *task )
{
if ( !task )
@@ -250,6 +250,22 @@ class CORE_EXPORT QgsTaskManager : public QObject
//! Will return true if the specified task has circular dependencies
bool hasCircularDependencies( long taskId ) const;

/** Sets a list of layers on which as task is dependent. The task will automatically
* be cancelled if any of these layers are above to be removed.
* @param taskId task ID
* @param layerIds list of layer IDs
* @see dependentLayers()
*/
void setDependentLayers( long taskId, const QStringList& layerIds );

/** Returns a list of layers on which as task is dependent. The task will automatically
* be cancelled if any of these layers are above to be removed.
* @param taskId task ID
* @returns list of layer IDs
* @see setDependentLayers()
*/
QStringList dependentLayers( long taskId ) const;

signals:

//! Will be emitted when a task reports a progress change
@@ -274,6 +290,7 @@ class CORE_EXPORT QgsTaskManager : public QObject

void taskProgressChanged( double progress );
void taskStatusChanged( int status );
void layersWillBeRemoved( const QStringList& layerIds );

private:

@@ -290,6 +307,7 @@ class CORE_EXPORT QgsTaskManager : public QObject

QMap< long, TaskInfo > mTasks;
QMap< long, QgsTaskList > mTaskDependencies;
QMap< long, QStringList > mLayerDependencies;

//! Tracks the next unique task ID
long mNextTaskId;
@@ -16,6 +16,9 @@
***************************************************************************/

#include "qgstaskmanager.h"
#include "qgsmaplayerregistry.h"
#include "qgsvectorlayer.h"
#include "qgsapplication.h"
#include <QObject>
#include <QSharedPointer>
#include <QtTest/QtTest>
@@ -86,19 +89,21 @@ class TestQgsTaskManager : public QObject
void statusChanged();
void holdTask();
void dependancies();
void layerDependencies();

private:

};

void TestQgsTaskManager::initTestCase()
{

QgsApplication::init();
QgsApplication::initQgis();
}

void TestQgsTaskManager::cleanupTestCase()
{

QgsApplication::exitQgis();
}

void TestQgsTaskManager::init()
@@ -440,6 +445,36 @@ void TestQgsTaskManager::dependancies()
QCOMPARE( grandChildTask->status(), QgsTask::Terminated );
}

void TestQgsTaskManager::layerDependencies()
{
//make some layers
QgsVectorLayer* layer1 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer1", "memory" );
QVERIFY( layer1->isValid() );
QgsVectorLayer* layer2 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer2", "memory" );
QVERIFY( layer2->isValid() );
QgsVectorLayer* layer3 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer3", "memory" );
QVERIFY( layer3->isValid() );
QgsMapLayerRegistry::instance()->addMapLayers( QList< QgsMapLayer* >() << layer1 << layer2 << layer3 );

QgsTaskManager manager;

//test that remove layers cancels all tasks which are dependant on them
TestTask* task = new TestTask();
task->hold();
long taskId = manager.addTask( task );
manager.setDependentLayers( taskId, QStringList() << layer2->id() << layer3->id() );

QCOMPARE( task->status(), QgsTask::OnHold );
//removing layer1 should have no effect
QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer1 );
QCOMPARE( task->status(), QgsTask::OnHold );
//removing layer3 should cancel task
QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer3 );
QCOMPARE( task->status(), QgsTask::Terminated );

QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer2 );
}


QTEST_MAIN( TestQgsTaskManager )
#include "testqgstaskmanager.moc"

0 comments on commit 55e9d32

Please sign in to comment.