Skip to content

Commit

Permalink
Add method to take results from another processing context and
Browse files Browse the repository at this point in the history
add to the current context

With appropriate note and tests to ensure that both the current
context and that which the results being taken from share the
same thread affinity
  • Loading branch information
nyalldawson committed Jul 6, 2017
1 parent d20c68d commit 5350483
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
9 changes: 9 additions & 0 deletions python/core/processing/qgsprocessingcontext.sip
Expand Up @@ -237,6 +237,15 @@ Destination project
.. seealso:: thread()
%End

void takeResultsFrom( QgsProcessingContext &context );
%Docstring
Takes the results from another ``context`` and merges them with the results currently
stored in this context. This includes settings like any layers loaded in the temporaryLayerStore()
and layersToLoadOnCompletion().
This is only safe to call when both this context and the other ``context`` share the same
thread() affinity, and that thread is the current thread.
%End

private:
QgsProcessingContext( const QgsProcessingContext &other );
};
Expand Down
21 changes: 20 additions & 1 deletion src/core/processing/qgsprocessingcontext.h
Expand Up @@ -340,10 +340,29 @@ class CORE_EXPORT QgsProcessingContext
*/
void pushToThread( QThread *thread )
{
Q_ASSERTX( QThread::currentThread() == thread(), "QgsProcessingContext::pushToThread", "Cannot push context to another thread unless the current thread matches the existing context thread affinity" );
Q_ASSERT_X( QThread::currentThread() == QgsProcessingContext::thread(), "QgsProcessingContext::pushToThread", "Cannot push context to another thread unless the current thread matches the existing context thread affinity" );
tempLayerStore.moveToThread( thread );
}

/**
* Takes the results from another \a context and merges them with the results currently
* stored in this context. This includes settings like any layers loaded in the temporaryLayerStore()
* and layersToLoadOnCompletion().
* This is only safe to call when both this context and the other \a context share the same
* thread() affinity, and that thread is the current thread.
*/
void takeResultsFrom( QgsProcessingContext &context )
{
QMap< QString, LayerDetails > loadOnCompletion = context.layersToLoadOnCompletion();
QMap< QString, LayerDetails >::const_iterator llIt = loadOnCompletion.constBegin();
for ( ; llIt != loadOnCompletion.constEnd(); ++llIt )
{
mLayersToLoadOnCompletion.insert( llIt.key(), llIt.value() );
}
context.setLayersToLoadOnCompletion( QMap< QString, LayerDetails >() );
tempLayerStore.transferLayersFromStore( context.temporaryLayerStore() );
}

private:

QgsProcessingContext::Flags mFlags = 0;
Expand Down
27 changes: 25 additions & 2 deletions tests/src/core/testqgsprocessing.cpp
Expand Up @@ -583,12 +583,18 @@ void TestQgsProcessing::context()
context.setInvalidGeometryCheck( QgsFeatureRequest::GeometrySkipInvalid );
QCOMPARE( context.invalidGeometryCheck(), QgsFeatureRequest::GeometrySkipInvalid );

QgsVectorLayer *vector = new QgsVectorLayer( "Polygon", "vector", "memory" );
context.temporaryLayerStore()->addMapLayer( vector );
QCOMPARE( context.temporaryLayerStore()->mapLayer( vector->id() ), vector );

QgsProcessingContext context2;
context2.copyThreadSafeSettings( context );
QCOMPARE( context2.defaultEncoding(), context.defaultEncoding() );
QCOMPARE( context2.invalidGeometryCheck(), context.invalidGeometryCheck() );
QCOMPARE( context2.flags(), context.flags() );
QCOMPARE( context2.project(), context.project() );
// layers from temporaryLayerStore must not be copied by copyThreadSafeSettings
QVERIFY( context2.temporaryLayerStore()->mapLayers().isEmpty() );

// layers to load on completion
QgsVectorLayer *v1 = new QgsVectorLayer( "Polygon", "V1", "memory" );
Expand All @@ -606,6 +612,11 @@ void TestQgsProcessing::context()
QCOMPARE( context.layersToLoadOnCompletion().values().at( 0 ).name, QStringLiteral( "v1" ) );
QCOMPARE( context.layersToLoadOnCompletion().keys().at( 1 ), v2->id() );
QCOMPARE( context.layersToLoadOnCompletion().values().at( 1 ).name, QStringLiteral( "v2" ) );

// ensure that copyThreadSafeSettings doesn't copy layersToLoadOnCompletion()
context2.copyThreadSafeSettings( context );
QVERIFY( context2.layersToLoadOnCompletion().isEmpty() );

layers.clear();
layers.insert( v2->id(), QgsProcessingContext::LayerDetails( QStringLiteral( "v2" ), &p ) );
context.setLayersToLoadOnCompletion( layers );
Expand All @@ -616,8 +627,20 @@ void TestQgsProcessing::context()
QCOMPARE( context.layersToLoadOnCompletion().count(), 2 );
QCOMPARE( context.layersToLoadOnCompletion().keys().at( 0 ), v1->id() );
QCOMPARE( context.layersToLoadOnCompletion().keys().at( 1 ), v2->id() );
delete v1;
delete v2;

context.temporaryLayerStore()->addMapLayer( v1 );
context.temporaryLayerStore()->addMapLayer( v2 );

// test takeResultsFrom
context2.takeResultsFrom( context );
QVERIFY( context.temporaryLayerStore()->mapLayers().isEmpty() );
QVERIFY( context.layersToLoadOnCompletion().isEmpty() );
// should now be in context2
QCOMPARE( context2.temporaryLayerStore()->mapLayer( v1->id() ), v1 );
QCOMPARE( context2.temporaryLayerStore()->mapLayer( v2->id() ), v2 );
QCOMPARE( context2.layersToLoadOnCompletion().count(), 2 );
QCOMPARE( context2.layersToLoadOnCompletion().keys().at( 0 ), v1->id() );
QCOMPARE( context2.layersToLoadOnCompletion().keys().at( 1 ), v2->id() );
}

void TestQgsProcessing::mapLayers()
Expand Down

0 comments on commit 5350483

Please sign in to comment.