Skip to content

Commit

Permalink
[processing] Add a model-only "load layer to project" algorithm
Browse files Browse the repository at this point in the history
This can be used to force loading a layer into the current project.
The primary use case here is to load a preset layer as part of a
model, but it's also useful for loading results from the
'package layers' algorithm into the project.
  • Loading branch information
nyalldawson committed Nov 26, 2017
1 parent bb63a83 commit 3310343
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/analysis/CMakeLists.txt
Expand Up @@ -41,6 +41,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmjoinbyattribute.cpp
processing/qgsalgorithmjoinwithlines.cpp
processing/qgsalgorithmlineintersection.cpp
processing/qgsalgorithmloadlayer.cpp
processing/qgsalgorithmmeancoordinates.cpp
processing/qgsalgorithmmergelines.cpp
processing/qgsalgorithmminimumenclosingcircle.cpp
Expand Down
83 changes: 83 additions & 0 deletions src/analysis/processing/qgsalgorithmloadlayer.cpp
@@ -0,0 +1,83 @@
/***************************************************************************
qgsalgorithmloadlayer.cpp
---------------------
begin : November 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsalgorithmloadlayer.h"

///@cond PRIVATE

QString QgsLoadLayerAlgorithm::name() const
{
return QStringLiteral( "loadlayer" );
}

QgsProcessingAlgorithm::Flags QgsLoadLayerAlgorithm::flags() const
{
return FlagHideFromToolbox;
}

QString QgsLoadLayerAlgorithm::displayName() const
{
return QObject::tr( "Load layer into project" );
}

QStringList QgsLoadLayerAlgorithm::tags() const
{
return QObject::tr( "load,open,layer,raster,vector,project" ).split( ',' );
}

QString QgsLoadLayerAlgorithm::group() const
{
return QObject::tr( "Modeler tool" );
}

QString QgsLoadLayerAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm loads a layer to the current project." );
}

QgsLoadLayerAlgorithm *QgsLoadLayerAlgorithm::createInstance() const
{
return new QgsLoadLayerAlgorithm();
}

void QgsLoadLayerAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterMapLayer( QStringLiteral( "INPUT" ), QObject::tr( "Layer" ) ) );
addParameter( new QgsProcessingParameterString( QStringLiteral( "NAME" ), QObject::tr( "Loaded layer name" ) ) );
addOutput( new QgsProcessingOutputMapLayer( QStringLiteral( "OUTPUT" ), QObject::tr( "Layer" ) ) );
}

QVariantMap QgsLoadLayerAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
QgsMapLayer *layer = parameterAsLayer( parameters, QStringLiteral( "INPUT" ), context );
QString name = parameterAsString( parameters, QStringLiteral( "NAME" ), context );

if ( !layer )
throw QgsProcessingException( QObject::tr( "Invalid input layer" ) );

if ( name.isEmpty() )
throw QgsProcessingException( QObject::tr( "Invalid (empty) layer name" ) );

layer->setName( name );
context.addLayerToLoadOnCompletion( layer->id(), QgsProcessingContext::LayerDetails( name, context.project(), name ) );

QVariantMap results;
results.insert( QStringLiteral( "OUTPUT" ), layer->id() );
return results;
}

///@endcond
53 changes: 53 additions & 0 deletions src/analysis/processing/qgsalgorithmloadlayer.h
@@ -0,0 +1,53 @@
/***************************************************************************
qgsalgorithmloadlayer.h
---------------------
begin : November 2017
copyright : (C) 2017 by Nyall Dawson
email : nyall dot dawson at gmail dot com
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSALGORITHMLOADLAYER_H
#define QGSALGORITHMLOADLAYER_H

#define SIP_NO_FILE

#include "qgis.h"
#include "qgsprocessingalgorithm.h"

///@cond PRIVATE

/**
* Native rename layer algorithm.
*/
class QgsLoadLayerAlgorithm : public QgsProcessingAlgorithm
{
public:
QgsLoadLayerAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
Flags flags() const override;
QString name() const override;
QString displayName() const override;
virtual QStringList tags() const override;
QString group() const override;
QString shortHelpString() const override;
QgsLoadLayerAlgorithm *createInstance() const override SIP_FACTORY;

protected:

virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback * ) override;

};

///@endcond PRIVATE

#endif // QGSALGORITHMLOADLAYER_H
2 changes: 2 additions & 0 deletions src/analysis/processing/qgsnativealgorithms.cpp
Expand Up @@ -38,6 +38,7 @@
#include "qgsalgorithmjoinbyattribute.h"
#include "qgsalgorithmjoinwithlines.h"
#include "qgsalgorithmlineintersection.h"
#include "qgsalgorithmloadlayer.h"
#include "qgsalgorithmmeancoordinates.h"
#include "qgsalgorithmmergelines.h"
#include "qgsalgorithmminimumenclosingcircle.h"
Expand Down Expand Up @@ -116,6 +117,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsJoinByAttributeAlgorithm() );
addAlgorithm( new QgsJoinWithLinesAlgorithm() );
addAlgorithm( new QgsLineIntersectionAlgorithm() );
addAlgorithm( new QgsLoadLayerAlgorithm() );
addAlgorithm( new QgsMeanCoordinatesAlgorithm() );
addAlgorithm( new QgsMergeLinesAlgorithm() );
addAlgorithm( new QgsMinimumEnclosingCircleAlgorithm() );
Expand Down
50 changes: 49 additions & 1 deletion tests/src/analysis/testqgsprocessingalgs.cpp
Expand Up @@ -35,9 +35,11 @@ class TestQgsProcessingAlgs: public QObject
void cleanup() {} // will be called after every testfunction.
void packageAlg();
void renameLayerAlg();
void loadLayerAlg();

private:

QString mPointLayerPath;
QgsVectorLayer *mPointsLayer = nullptr;
QgsVectorLayer *mPolygonLayer = nullptr;

Expand All @@ -59,7 +61,8 @@ void TestQgsProcessingAlgs::initTestCase()

QString pointsFileName = dataDir + "/points.shp";
QFileInfo pointFileInfo( pointsFileName );
mPointsLayer = new QgsVectorLayer( pointFileInfo.filePath(),
mPointLayerPath = pointFileInfo.filePath();
mPointsLayer = new QgsVectorLayer( mPointLayerPath,
QStringLiteral( "points" ), QStringLiteral( "ogr" ) );
QVERIFY( mPointsLayer->isValid() );
// Register the layer with the registry
Expand Down Expand Up @@ -169,6 +172,51 @@ void TestQgsProcessingAlgs::renameLayerAlg()
QCOMPARE( results.value( "OUTPUT" ).toString(), QStringLiteral( "new name2" ) );
}

void TestQgsProcessingAlgs::loadLayerAlg()
{
const QgsProcessingAlgorithm *package( QgsApplication::processingRegistry()->algorithmById( QStringLiteral( "native:loadlayer" ) ) );
QVERIFY( package );

std::unique_ptr< QgsProcessingContext > context = qgis::make_unique< QgsProcessingContext >();
QgsProject p;
context->setProject( &p );

QgsProcessingFeedback feedback;

QVariantMap parameters;

// bad layer
parameters.insert( QStringLiteral( "INPUT" ), QStringLiteral( "bad layer" ) );
parameters.insert( QStringLiteral( "NAME" ), QStringLiteral( "new name" ) );
bool ok = false;
( void )package->run( parameters, *context, &feedback, &ok );
QVERIFY( !ok );
QVERIFY( context->layersToLoadOnCompletion().empty() );

//invalid name
parameters.insert( QStringLiteral( "INPUT" ), mPointLayerPath );
parameters.insert( QStringLiteral( "NAME" ), QString() );
ok = false;
( void )package->run( parameters, *context, &feedback, &ok );
QVERIFY( !ok );
QVERIFY( context->layersToLoadOnCompletion().empty() );

//good params
parameters.insert( QStringLiteral( "INPUT" ), mPointLayerPath );
parameters.insert( QStringLiteral( "NAME" ), QStringLiteral( "my layer" ) );
ok = false;
QVariantMap results = package->run( parameters, *context, &feedback, &ok );
QVERIFY( ok );
QVERIFY( !context->layersToLoadOnCompletion().empty() );
QString layerId = context->layersToLoadOnCompletion().keys().at( 0 );
QCOMPARE( results.value( QStringLiteral( "OUTPUT" ) ).toString(), layerId );
QVERIFY( !layerId.isEmpty() );
QVERIFY( context->temporaryLayerStore()->mapLayer( layerId ) );
QCOMPARE( context->layersToLoadOnCompletion().value( layerId, QgsProcessingContext::LayerDetails( QString(), nullptr, QString() ) ).name, QStringLiteral( "my layer" ) );
QCOMPARE( context->layersToLoadOnCompletion().value( layerId, QgsProcessingContext::LayerDetails( QString(), nullptr, QString() ) ).project, &p );
QCOMPARE( context->layersToLoadOnCompletion().value( layerId, QgsProcessingContext::LayerDetails( QString(), nullptr, QString() ) ).outputName, QStringLiteral( "my layer" ) );
}


QGSTEST_MAIN( TestQgsProcessingAlgs )
#include "testqgsprocessingalgs.moc"

0 comments on commit 3310343

Please sign in to comment.