Skip to content

Commit 55e9d32

Browse files
committed
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
1 parent eb34079 commit 55e9d32

File tree

4 files changed

+111
-3
lines changed

4 files changed

+111
-3
lines changed

python/core/qgstaskmanager.sip

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,22 @@ class QgsTaskManager : QObject
219219
//! Will return true if the specified task has circular dependencies
220220
bool hasCircularDependencies( long taskId ) const;
221221

222+
/** Sets a list of layers on which as task is dependent. The task will automatically
223+
* be cancelled if any of these layers are above to be removed.
224+
* @param taskId task ID
225+
* @param layerIds list of layer IDs
226+
* @see dependentLayers()
227+
*/
228+
void setDependentLayers( long taskId, const QStringList& layerIds );
229+
230+
/** Returns a list of layers on which as task is dependent. The task will automatically
231+
* be cancelled if any of these layers are above to be removed.
232+
* @param taskId task ID
233+
* @returns list of layer IDs
234+
* @see setDependentLayers()
235+
*/
236+
QStringList dependentLayers( long taskId ) const;
237+
222238
signals:
223239

224240
//! Will be emitted when a task reports a progress change

src/core/qgstaskmanager.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
***************************************************************************/
1717

1818
#include "qgstaskmanager.h"
19+
#include "qgsmaplayerregistry.h"
1920
#include <QtConcurrentRun>
2021

2122

@@ -108,7 +109,10 @@ QgsTaskManager *QgsTaskManager::instance()
108109
QgsTaskManager::QgsTaskManager( QObject* parent )
109110
: QObject( parent )
110111
, mNextTaskId( 0 )
111-
{}
112+
{
113+
connect( QgsMapLayerRegistry::instance(), SIGNAL( layersWillBeRemoved( QStringList ) ),
114+
this, SLOT( layersWillBeRemoved( QStringList ) ) );
115+
}
112116

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

283+
void QgsTaskManager::setDependentLayers( long taskId, const QStringList& layerIds )
284+
{
285+
mLayerDependencies.insert( taskId, layerIds );
286+
}
287+
288+
QStringList QgsTaskManager::dependentLayers( long taskId ) const
289+
{
290+
return mLayerDependencies.value( taskId, QStringList() );
291+
}
292+
279293
void QgsTaskManager::taskProgressChanged( double progress )
280294
{
281295
QgsTask* task = qobject_cast< QgsTask* >( sender() );
@@ -307,6 +321,31 @@ void QgsTaskManager::taskStatusChanged( int status )
307321
processQueue();
308322
}
309323

324+
void QgsTaskManager::layersWillBeRemoved( const QStringList& layerIds )
325+
{
326+
// scan through layers to be removed
327+
Q_FOREACH ( const QString& layerId, layerIds )
328+
{
329+
// scan through tasks with layer dependencies
330+
for ( QMap< long, QStringList >::const_iterator it = mLayerDependencies.constBegin();
331+
it != mLayerDependencies.constEnd(); ++it )
332+
{
333+
if ( !it.value().contains( layerId ) )
334+
{
335+
//task not dependent on this layer
336+
continue;
337+
}
338+
339+
QgsTask* dependentTask = task( it.key() );
340+
if ( dependentTask && ( dependentTask->status() != QgsTask::Complete || dependentTask->status() != QgsTask::Terminated ) )
341+
{
342+
// incomplete task is dependent on this layer!
343+
dependentTask->cancel();
344+
}
345+
}
346+
}
347+
}
348+
310349
bool QgsTaskManager::cleanupAndDeleteTask( QgsTask *task )
311350
{
312351
if ( !task )

src/core/qgstaskmanager.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,22 @@ class CORE_EXPORT QgsTaskManager : public QObject
250250
//! Will return true if the specified task has circular dependencies
251251
bool hasCircularDependencies( long taskId ) const;
252252

253+
/** Sets a list of layers on which as task is dependent. The task will automatically
254+
* be cancelled if any of these layers are above to be removed.
255+
* @param taskId task ID
256+
* @param layerIds list of layer IDs
257+
* @see dependentLayers()
258+
*/
259+
void setDependentLayers( long taskId, const QStringList& layerIds );
260+
261+
/** Returns a list of layers on which as task is dependent. The task will automatically
262+
* be cancelled if any of these layers are above to be removed.
263+
* @param taskId task ID
264+
* @returns list of layer IDs
265+
* @see setDependentLayers()
266+
*/
267+
QStringList dependentLayers( long taskId ) const;
268+
253269
signals:
254270

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

275291
void taskProgressChanged( double progress );
276292
void taskStatusChanged( int status );
293+
void layersWillBeRemoved( const QStringList& layerIds );
277294

278295
private:
279296

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

291308
QMap< long, TaskInfo > mTasks;
292309
QMap< long, QgsTaskList > mTaskDependencies;
310+
QMap< long, QStringList > mLayerDependencies;
293311

294312
//! Tracks the next unique task ID
295313
long mNextTaskId;

tests/src/core/testqgstaskmanager.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
***************************************************************************/
1717

1818
#include "qgstaskmanager.h"
19+
#include "qgsmaplayerregistry.h"
20+
#include "qgsvectorlayer.h"
21+
#include "qgsapplication.h"
1922
#include <QObject>
2023
#include <QSharedPointer>
2124
#include <QtTest/QtTest>
@@ -86,19 +89,21 @@ class TestQgsTaskManager : public QObject
8689
void statusChanged();
8790
void holdTask();
8891
void dependancies();
92+
void layerDependencies();
8993

9094
private:
9195

9296
};
9397

9498
void TestQgsTaskManager::initTestCase()
9599
{
96-
100+
QgsApplication::init();
101+
QgsApplication::initQgis();
97102
}
98103

99104
void TestQgsTaskManager::cleanupTestCase()
100105
{
101-
106+
QgsApplication::exitQgis();
102107
}
103108

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

448+
void TestQgsTaskManager::layerDependencies()
449+
{
450+
//make some layers
451+
QgsVectorLayer* layer1 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer1", "memory" );
452+
QVERIFY( layer1->isValid() );
453+
QgsVectorLayer* layer2 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer2", "memory" );
454+
QVERIFY( layer2->isValid() );
455+
QgsVectorLayer* layer3 = new QgsVectorLayer( "Point?field=col1:string&field=col2:string&field=col3:string", "layer3", "memory" );
456+
QVERIFY( layer3->isValid() );
457+
QgsMapLayerRegistry::instance()->addMapLayers( QList< QgsMapLayer* >() << layer1 << layer2 << layer3 );
458+
459+
QgsTaskManager manager;
460+
461+
//test that remove layers cancels all tasks which are dependant on them
462+
TestTask* task = new TestTask();
463+
task->hold();
464+
long taskId = manager.addTask( task );
465+
manager.setDependentLayers( taskId, QStringList() << layer2->id() << layer3->id() );
466+
467+
QCOMPARE( task->status(), QgsTask::OnHold );
468+
//removing layer1 should have no effect
469+
QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer1 );
470+
QCOMPARE( task->status(), QgsTask::OnHold );
471+
//removing layer3 should cancel task
472+
QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer3 );
473+
QCOMPARE( task->status(), QgsTask::Terminated );
474+
475+
QgsMapLayerRegistry::instance()->removeMapLayers( QList< QgsMapLayer* >() << layer2 );
476+
}
477+
443478

444479
QTEST_MAIN( TestQgsTaskManager )
445480
#include "testqgstaskmanager.moc"

0 commit comments

Comments
 (0)