Skip to content
Permalink
Browse files

Merge pull request #5650 from nyalldawson/proc_gpkg

[FEATURE][processing] Package layers algorithm
  • Loading branch information
nyalldawson committed Nov 23, 2017
2 parents b288a5f + 0a18b1f commit d2369425c62045fb7c2da477d64c9d3ca4492c86
@@ -179,6 +179,7 @@
%Include processing/qgsprocessingoutputs.sip
%Include processing/qgsprocessingparameters.sip
%Include processing/qgsprocessingutils.sip
%Include processing/models/qgsprocessingmodelalgorithm.sip
%Include processing/models/qgsprocessingmodelchildalgorithm.sip
%Include processing/models/qgsprocessingmodelchildparametersource.sip
%Include processing/models/qgsprocessingmodelcomponent.sip
@@ -391,7 +392,6 @@
%Include processing/qgsprocessingfeedback.sip
%Include processing/qgsprocessingprovider.sip
%Include processing/qgsprocessingregistry.sip
%Include processing/models/qgsprocessingmodelalgorithm.sip
%Include raster/qgsrasterfilewritertask.sip
%Include raster/qgsrasterlayer.sip
%Include raster/qgsrasterdataprovider.sip
@@ -374,8 +374,6 @@ Translated description of variable
};




/************************************************************************
* This file has been generated automatically from *
* *
@@ -80,6 +80,52 @@ class QgsProcessingFeedback : QgsFeedback
};


class QgsProcessingMultiStepFeedback : QgsProcessingFeedback
{
%Docstring

Processing feedback object for multi-step operations.

A processing feedback object which proxies its calls to an underlying
feedback object, but scales overall progress reports to account
for a number of child steps which each report their own feedback.

.. versionadded:: 3.0
%End

%TypeHeaderCode
#include "qgsprocessingfeedback.h"
%End
public:

QgsProcessingMultiStepFeedback( int steps, QgsProcessingFeedback *feedback );
%Docstring
Constructor for QgsProcessingMultiStepFeedback, for a process with the specified
number of ``steps``. This feedback object will proxy calls
to the specified ``feedback`` object.
%End

void setCurrentStep( int step );
%Docstring
Sets the ``step`` which is being executed. This is used
to scale the current progress to account for progress through the overall process.
%End

virtual void setProgressText( const QString &text );

virtual void reportError( const QString &error );

virtual void pushInfo( const QString &info );

virtual void pushCommandInfo( const QString &info );

virtual void pushDebugInfo( const QString &info );

virtual void pushConsoleInfo( const QString &info );


};



/************************************************************************
@@ -46,6 +46,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmminimumenclosingcircle.cpp
processing/qgsalgorithmmultiparttosinglepart.cpp
processing/qgsalgorithmorientedminimumboundingbox.cpp
processing/qgsalgorithmpackage.cpp
processing/qgsalgorithmpromotetomultipart.cpp
processing/qgsalgorithmrasterlayeruniquevalues.cpp
processing/qgsalgorithmremovenullgeometry.cpp
@@ -0,0 +1,169 @@
/***************************************************************************
qgsalgorithmpackage.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 "qgsalgorithmpackage.h"
#include "qgsgeometryengine.h"
#include "qgsogrutils.h"
#include "qgsvectorfilewriter.h"

///@cond PRIVATE

QString QgsPackageAlgorithm::name() const
{
return QStringLiteral( "package" );
}

QString QgsPackageAlgorithm::displayName() const
{
return QObject::tr( "Package layers" );
}

QStringList QgsPackageAlgorithm::tags() const
{
return QObject::tr( "geopackage,collect,merge,combine" ).split( ',' );
}

QString QgsPackageAlgorithm::group() const
{
return QObject::tr( "Database" );
}

void QgsPackageAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterMultipleLayers( QStringLiteral( "LAYERS" ), QObject::tr( "Input layers" ), QgsProcessing::TypeVector ) );
addParameter( new QgsProcessingParameterFileDestination( QStringLiteral( "OUTPUT" ), QObject::tr( "Destination GeoPackage" ), QStringLiteral( "*.gpkg" ) ) );
addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "OVERWRITE" ), QObject::tr( "Overwrite existing GeoPackage" ), false ) );
}

QString QgsPackageAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm collects a number of existing layers and packages them together into a single GeoPackage database." );
}

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

QVariantMap QgsPackageAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
bool overwrite = parameterAsBool( parameters, QStringLiteral( "OVERWRITE" ), context );
QString packagePath = parameterAsString( parameters, QStringLiteral( "OUTPUT" ), context );
if ( packagePath.isEmpty() )
throw QgsProcessingException( QObject::tr( "No output file specified." ) );

// delete existing geopackage if it exists
if ( overwrite && QFile::exists( packagePath ) )
{
feedback->pushInfo( QObject::tr( "Removing existing file '%1'" ).arg( packagePath ) );
if ( !QFile( packagePath ).remove() )
{
throw QgsProcessingException( QObject::tr( "Could not remove existing file '%1'" ) );
}
}

OGRSFDriverH hGpkgDriver = OGRGetDriverByName( "GPKG" );
if ( !hGpkgDriver )
{
throw QgsProcessingException( QObject::tr( "GeoPackage driver not found." ) );
}

gdal::ogr_datasource_unique_ptr hDS( OGR_Dr_CreateDataSource( hGpkgDriver, packagePath.toUtf8().constData(), nullptr ) );
if ( !hDS )
throw QgsProcessingException( QObject::tr( "Creation of database failed (OGR error: %1)" ).arg( QString::fromUtf8( CPLGetLastErrorMsg() ) ) );

bool errored = false;
const QList< QgsMapLayer * > layers = parameterAsLayerList( parameters, QStringLiteral( "LAYERS" ), context );

QgsProcessingMultiStepFeedback multiStepFeedback( layers.count(), feedback );

int i = 0;
for ( QgsMapLayer *layer : layers )
{
if ( feedback->isCanceled() )
break;

multiStepFeedback.setCurrentStep( i );
i++;

feedback->pushInfo( QObject::tr( "Packaging layer %1/%2: %3" ).arg( i ).arg( layers.count() ).arg( layer->name() ) );

if ( !layer )
{
// don't throw immediately - instead do what we can and error out later
feedback->pushDebugInfo( QObject::tr( "Error retrieving map layer." ) );
errored = true;
continue;
}

switch ( layer->type() )
{
case QgsMapLayer::VectorLayer:
{
if ( !packageVectorLayer( qobject_cast< QgsVectorLayer * >( layer ), packagePath,
context, &multiStepFeedback ) )
errored = true;
break;
}

case QgsMapLayer::RasterLayer:
{
//not supported
feedback->pushDebugInfo( QObject::tr( "Raster layers are not currently supported." ) );
errored = true;
break;
}

case QgsMapLayer::PluginLayer:
//not supported
feedback->pushDebugInfo( QObject::tr( "Packaging plugin layers is not supported." ) );
errored = true;
break;
}
}

if ( errored )
throw QgsProcessingException( QObject::tr( "Error obtained while packaging one or more layers." ) );

QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), packagePath );
return outputs;
}

bool QgsPackageAlgorithm::packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context,
QgsProcessingFeedback *feedback )
{
QgsVectorFileWriter::SaveVectorOptions options;
options.driverName = QStringLiteral( "GPKG" );
options.layerName = layer->name();
options.actionOnExistingFile = QgsVectorFileWriter::CreateOrOverwriteLayer;
options.fileEncoding = context.defaultEncoding();
options.feedback = feedback;

QString error;
if ( QgsVectorFileWriter::writeAsVectorFormat( layer, path, options, &error ) != QgsVectorFileWriter::NoError )
{
feedback->pushDebugInfo( QObject::tr( "Packaging layer failed: %1" ).arg( error ) );
return false;
}
else
{
return true;
}
}

///@endcond
@@ -0,0 +1,62 @@
/***************************************************************************
qgsalgorithmpackage.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 QGSALGORITHMPACKAGE_H
#define QGSALGORITHMPACKAGE_H

#define SIP_NO_FILE

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

///@cond PRIVATE

class QgsVectorLayer;

/**
* Native package layers algorithm.
*/
class QgsPackageAlgorithm : public QgsProcessingAlgorithm
{

public:

QgsPackageAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
virtual QStringList tags() const override;
QString group() const override;
QString shortHelpString() const override;
QgsPackageAlgorithm *createInstance() const override SIP_FACTORY;

protected:

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

private:

bool packageVectorLayer( QgsVectorLayer *layer, const QString &path, QgsProcessingContext &context, QgsProcessingFeedback *feedback );

};

///@endcond PRIVATE

#endif // QGSALGORITHMPACKAGE_H


@@ -43,6 +43,7 @@
#include "qgsalgorithmminimumenclosingcircle.h"
#include "qgsalgorithmmultiparttosinglepart.h"
#include "qgsalgorithmorientedminimumboundingbox.h"
#include "qgsalgorithmpackage.h"
#include "qgsalgorithmpromotetomultipart.h"
#include "qgsalgorithmrasterlayeruniquevalues.h"
#include "qgsalgorithmremovenullgeometry.h"
@@ -118,6 +119,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsMinimumEnclosingCircleAlgorithm() );
addAlgorithm( new QgsMultipartToSinglepartAlgorithm() );
addAlgorithm( new QgsOrientedMinimumBoundingBoxAlgorithm() );
addAlgorithm( new QgsPackageAlgorithm() );
addAlgorithm( new QgsPromoteToMultipartAlgorithm() );
addAlgorithm( new QgsRasterLayerUniqueValuesReportAlgorithm() );
addAlgorithm( new QgsRemoveNullGeometryAlgorithm() );
@@ -100,6 +100,7 @@ SET(QGIS_CORE_SRCS

processing/qgsprocessingalgorithm.cpp
processing/qgsprocessingalgrunnertask.cpp
processing/qgsprocessingfeedback.cpp
processing/qgsprocessingoutputs.cpp
processing/qgsprocessingparameters.cpp
processing/qgsprocessingprovider.cpp
@@ -706,7 +707,6 @@ SET(QGIS_CORE_MOC_HDRS
processing/qgsprocessingfeedback.h
processing/qgsprocessingprovider.h
processing/qgsprocessingregistry.h
processing/models/qgsprocessingmodelalgorithm.h

providers/memory/qgsmemoryprovider.h

@@ -1024,6 +1024,7 @@ SET(QGIS_CORE_HDRS
processing/qgsprocessingoutputs.h
processing/qgsprocessingparameters.h
processing/qgsprocessingutils.h
processing/models/qgsprocessingmodelalgorithm.h
processing/models/qgsprocessingmodelchildalgorithm.h
processing/models/qgsprocessingmodelchildparametersource.h
processing/models/qgsprocessingmodelcomponent.h

0 comments on commit d236942

Please sign in to comment.
You can’t perform that action at this time.