Skip to content

Commit

Permalink
[processing] Fix incorrect OGR warnings when loading raster layer res…
Browse files Browse the repository at this point in the history
…ults

Fixes #19597

(cherry-picked from 4930061)
  • Loading branch information
nyalldawson committed Aug 16, 2018
1 parent 9ae1a32 commit 4103614
Show file tree
Hide file tree
Showing 9 changed files with 137 additions and 39 deletions.
Expand Up @@ -126,7 +126,7 @@ Details for layers to load into projects.
%End
public:

LayerDetails( const QString &name, QgsProject *project, const QString &outputName = QString() );
LayerDetails( const QString &name, QgsProject *project, const QString &outputName = QString(), QgsProcessingUtils::LayerHint layerTypeHint = QgsProcessingUtils::UnknownType );
%Docstring
Constructor for LayerDetails.
%End
Expand All @@ -140,6 +140,8 @@ Default constructor

QString outputName;

QgsProcessingUtils::LayerHint layerTypeHint;

QgsProcessingLayerPostProcessorInterface *postProcessor() const;
%Docstring
Layer post-processor. May be None if no post-processing is required.
Expand Down
11 changes: 10 additions & 1 deletion python/core/auto_generated/processing/qgsprocessingutils.sip.in
Expand Up @@ -71,7 +71,14 @@ value.
.. seealso:: :py:func:`compatibleVectorLayers`
%End

static QgsMapLayer *mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers = true );
enum LayerHint
{
UnknownType,
Vector,
Raster,
};

static QgsMapLayer *mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers = true, LayerHint typeHint = UnknownType );
%Docstring
Interprets a string as a map layer within the supplied ``context``.

Expand All @@ -81,6 +88,8 @@ within the context's project or temporary layer store then this layer will be re
If the string is a file path and ``allowLoadingNewLayers`` is true, then the layer at this
file path will be loaded and added to the context's temporary layer store.
Ownership of the layer remains with the ``context`` or the context's current project.

The ``typeHint`` can be used to dictate the type of map layer expected.
%End

static QgsProcessingFeatureSource *variantToSource( const QVariant &value, QgsProcessingContext &context, const QVariant &fallbackValue = QVariant() ) /Factory/;
Expand Down
2 changes: 1 addition & 1 deletion python/plugins/processing/gui/Postprocessing.py
Expand Up @@ -57,7 +57,7 @@ def handleAlgorithmResults(alg, context, feedback=None, showResults=True):
feedback.setProgress(100 * i / float(len(context.layersToLoadOnCompletion())))

try:
layer = QgsProcessingUtils.mapLayerFromString(l, context)
layer = QgsProcessingUtils.mapLayerFromString(l, context, typeHint=details.layerTypeHint)
if layer is not None:
if not ProcessingConfig.getSetting(ProcessingConfig.USE_FILENAME_AS_LAYER_NAME):
layer.setName(details.name)
Expand Down
2 changes: 1 addition & 1 deletion src/core/processing/models/qgsprocessingmodelalgorithm.cpp
Expand Up @@ -591,7 +591,7 @@ QMap<QString, QgsProcessingModelAlgorithm::VariableDefinition> QgsProcessingMode
}
if ( !featureSource )
{
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( value.toString(), context ) ) )
if ( QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( value.toString(), context, true, QgsProcessingUtils::Vector ) ) )
featureSource = vl;
}

Expand Down
11 changes: 10 additions & 1 deletion src/core/processing/qgsprocessingcontext.h
Expand Up @@ -26,6 +26,7 @@
#include "qgsmaplayerlistutils.h"
#include "qgsexception.h"
#include "qgsprocessingfeedback.h"
#include "qgsprocessingutils.h"

class QgsProcessingLayerPostProcessorInterface;

Expand Down Expand Up @@ -169,9 +170,10 @@ class CORE_EXPORT QgsProcessingContext
/**
* Constructor for LayerDetails.
*/
LayerDetails( const QString &name, QgsProject *project, const QString &outputName = QString() )
LayerDetails( const QString &name, QgsProject *project, const QString &outputName = QString(), QgsProcessingUtils::LayerHint layerTypeHint = QgsProcessingUtils::UnknownType )
: name( name )
, outputName( outputName )
, layerTypeHint( layerTypeHint )
, project( project )
{}

Expand All @@ -184,6 +186,13 @@ class CORE_EXPORT QgsProcessingContext
//! Associated output name from algorithm which generated the layer.
QString outputName;

/**
* Layer type hint.
*
* \since QGIS 3.4
*/
QgsProcessingUtils::LayerHint layerTypeHint = QgsProcessingUtils::UnknownType;

/**
* Layer post-processor. May be nullptr if no post-processing is required.
* \see setPostProcessor()
Expand Down
23 changes: 15 additions & 8 deletions src/core/processing/qgsprocessingparameters.cpp
Expand Up @@ -290,7 +290,7 @@ QgsFeatureSink *QgsProcessingParameters::parameterAsSink( const QgsProcessingPar
QString outputName;
if ( definition )
outputName = definition->name();
context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName ) );
context.addLayerToLoadOnCompletion( destinationIdentifier, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, QgsProcessingUtils::Vector ) );
}

return sink.release();
Expand Down Expand Up @@ -363,7 +363,7 @@ QString QgsProcessingParameters::parameterAsCompatibleSourceLayerPath( const Qgs
if ( layerRef.isEmpty() )
return QString();

vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context ) );
vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, QgsProcessingUtils::Vector ) );
}
}

Expand Down Expand Up @@ -462,7 +462,14 @@ QString QgsProcessingParameters::parameterAsOutputLayer( const QgsProcessingPara
}
if ( definition )
outputName = definition->name();
context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName ) );

QgsProcessingUtils::LayerHint layerTypeHint = QgsProcessingUtils::UnknownType;
if ( definition->type() == QgsProcessingParameterVectorDestination::typeName() )
layerTypeHint = QgsProcessingUtils::Vector;
else if ( definition->type() == QgsProcessingParameterRasterDestination::typeName() )
layerTypeHint = QgsProcessingUtils::Raster;

context.addLayerToLoadOnCompletion( dest, QgsProcessingContext::LayerDetails( destName, destinationProject, outputName, layerTypeHint ) );
}

return dest;
Expand Down Expand Up @@ -2450,7 +2457,7 @@ bool QgsProcessingParameterRasterLayer::checkValueIsAcceptable( const QVariant &
}

// try to load as layer
if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context ) )
if ( QgsProcessingUtils::mapLayerFromString( input.toString(), *context, true, QgsProcessingUtils::Raster ) )
return true;

return false;
Expand Down Expand Up @@ -2849,7 +2856,7 @@ bool QgsProcessingParameterVectorLayer::checkValueIsAcceptable( const QVariant &
}

// try to load as layer
if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context ) )
if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::Vector ) )
return true;

return false;
Expand Down Expand Up @@ -3180,7 +3187,7 @@ bool QgsProcessingParameterFeatureSource::checkValueIsAcceptable( const QVariant
}

// try to load as layer
if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context ) )
if ( QgsProcessingUtils::mapLayerFromString( var.toString(), *context, true, QgsProcessingUtils::Vector ) )
return true;

return false;
Expand All @@ -3207,7 +3214,7 @@ QString QgsProcessingParameterFeatureSource::valueAsPythonString( const QVariant
{
QString layerString = fromVar.source.staticValue().toString();
// prefer to use layer source instead of id if possible (since it's persistent)
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context ) ) )
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::Vector ) ) )
layerString = layer->source();
return QgsProcessingUtils::stringToPythonLiteral( layerString );
}
Expand All @@ -3232,7 +3239,7 @@ QString QgsProcessingParameterFeatureSource::valueAsPythonString( const QVariant
QString layerString = value.toString();

// prefer to use layer source if possible (since it's persistent)
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context ) ) )
if ( QgsVectorLayer *layer = qobject_cast< QgsVectorLayer * >( QgsProcessingUtils::mapLayerFromString( layerString, context, true, QgsProcessingUtils::Vector ) ) )
layerString = layer->source();

return QgsProcessingUtils::stringToPythonLiteral( layerString );
Expand Down
68 changes: 45 additions & 23 deletions src/core/processing/qgsprocessingutils.cpp
Expand Up @@ -94,7 +94,7 @@ QList<QgsMapLayer *> QgsProcessingUtils::compatibleLayers( QgsProject *project,
return layers;
}

QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store )
QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMapLayerStore *store, QgsProcessingUtils::LayerHint typeHint )
{
if ( !store || string.isEmpty() )
return nullptr;
Expand All @@ -117,19 +117,35 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMa
return true;
} ), layers.end() );

Q_FOREACH ( QgsMapLayer *l, layers )
auto isCompatibleType = [typeHint]( QgsMapLayer * l ) -> bool
{
if ( l->id() == string )
switch ( typeHint )
{
case UnknownType:
return true;

case Vector:
return l->type() == QgsMapLayer::VectorLayer;

case Raster:
return l->type() == QgsMapLayer::RasterLayer;
}
return true;
};

for ( QgsMapLayer *l : qgis::as_const( layers ) )
{
if ( isCompatibleType( l ) && l->id() == string )
return l;
}
Q_FOREACH ( QgsMapLayer *l, layers )
for ( QgsMapLayer *l : qgis::as_const( layers ) )
{
if ( l->name() == string )
if ( isCompatibleType( l ) && l->name() == string )
return l;
}
Q_FOREACH ( QgsMapLayer *l, layers )
for ( QgsMapLayer *l : qgis::as_const( layers ) )
{
if ( normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
if ( isCompatibleType( l ) && normalizeLayerSource( l->source() ) == normalizeLayerSource( string ) )
return l;
}
return nullptr;
Expand Down Expand Up @@ -157,7 +173,7 @@ class ProjectionSettingRestorer
};
///@endcond PRIVATE

QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string )
QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, LayerHint typeHint )
{
QStringList components = string.split( '|' );
if ( components.isEmpty() )
Expand All @@ -178,24 +194,30 @@ QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string )
QString name = fi.baseName();

// brute force attempt to load a matching layer
QgsVectorLayer::LayerOptions options;
options.loadDefaultStyle = false;
std::unique_ptr< QgsVectorLayer > layer( new QgsVectorLayer( string, name, QStringLiteral( "ogr" ), options ) );
if ( layer->isValid() )
if ( typeHint == UnknownType || typeHint == Vector )
{
return layer.release();
QgsVectorLayer::LayerOptions options;
options.loadDefaultStyle = false;
std::unique_ptr< QgsVectorLayer > layer( new QgsVectorLayer( string, name, QStringLiteral( "ogr" ), options ) );
if ( layer->isValid() )
{
return layer.release();
}
}
QgsRasterLayer::LayerOptions rasterOptions;
rasterOptions.loadDefaultStyle = false;
std::unique_ptr< QgsRasterLayer > rasterLayer( new QgsRasterLayer( string, name, QStringLiteral( "gdal" ), rasterOptions ) );
if ( rasterLayer->isValid() )
if ( typeHint == UnknownType || typeHint == Raster )
{
return rasterLayer.release();
QgsRasterLayer::LayerOptions rasterOptions;
rasterOptions.loadDefaultStyle = false;
std::unique_ptr< QgsRasterLayer > rasterLayer( new QgsRasterLayer( string, name, QStringLiteral( "gdal" ), rasterOptions ) );
if ( rasterLayer->isValid() )
{
return rasterLayer.release();
}
}
return nullptr;
}

QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers )
QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers, LayerHint typeHint )
{
if ( string.isEmpty() )
return nullptr;
Expand All @@ -204,19 +226,19 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromString( const QString &string, QgsP
QgsMapLayer *layer = nullptr;
if ( context.project() )
{
QgsMapLayer *layer = mapLayerFromStore( string, context.project()->layerStore() );
QgsMapLayer *layer = mapLayerFromStore( string, context.project()->layerStore(), typeHint );
if ( layer )
return layer;
}

layer = mapLayerFromStore( string, context.temporaryLayerStore() );
layer = mapLayerFromStore( string, context.temporaryLayerStore(), typeHint );
if ( layer )
return layer;

if ( !allowLoadingNewLayers )
return nullptr;

layer = loadMapLayerFromString( string );
layer = loadMapLayerFromString( string, typeHint );
if ( layer )
{
context.temporaryLayerStore()->addMapLayer( layer );
Expand Down Expand Up @@ -274,7 +296,7 @@ QgsProcessingFeatureSource *QgsProcessingUtils::variantToSource( const QVariant
if ( layerRef.isEmpty() )
return nullptr;

QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context ) );
QgsVectorLayer *vl = qobject_cast< QgsVectorLayer *>( QgsProcessingUtils::mapLayerFromString( layerRef, context, true, Vector ) );
if ( !vl )
return nullptr;

Expand Down
19 changes: 16 additions & 3 deletions src/core/processing/qgsprocessingutils.h
Expand Up @@ -86,6 +86,17 @@ class CORE_EXPORT QgsProcessingUtils
*/
static QList< QgsMapLayer * > compatibleLayers( QgsProject *project, bool sort = true );

/**
* Layer type hints.
* \since QGIS 3.4
*/
enum LayerHint
{
UnknownType, //!< Unknown layer type
Vector, //!< Vector layer type
Raster, //!< Raster layer type
};

/**
* Interprets a string as a map layer within the supplied \a context.
*
Expand All @@ -95,8 +106,10 @@ class CORE_EXPORT QgsProcessingUtils
* If the string is a file path and \a allowLoadingNewLayers is true, then the layer at this
* file path will be loaded and added to the context's temporary layer store.
* Ownership of the layer remains with the \a context or the context's current project.
*
* The \a typeHint can be used to dictate the type of map layer expected.
*/
static QgsMapLayer *mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers = true );
static QgsMapLayer *mapLayerFromString( const QString &string, QgsProcessingContext &context, bool allowLoadingNewLayers = true, LayerHint typeHint = UnknownType );

/**
* Converts a variant \a value to a new feature source.
Expand Down Expand Up @@ -265,15 +278,15 @@ class CORE_EXPORT QgsProcessingUtils
* returned.
* \see mapLayerFromString()
*/
static QgsMapLayer *mapLayerFromStore( const QString &string, QgsMapLayerStore *store );
static QgsMapLayer *mapLayerFromStore( const QString &string, QgsMapLayerStore *store, LayerHint typeHint = UnknownType );

/**
* Interprets a string as a map layer. The method will attempt to
* load a layer matching the passed \a string. E.g. if the string is a file path,
* then the layer at this file path will be loaded.
* The caller takes responsibility for deleting the returned map layer.
*/
static QgsMapLayer *loadMapLayerFromString( const QString &string );
static QgsMapLayer *loadMapLayerFromString( const QString &string, LayerHint typeHint = UnknownType );

static void parseDestinationString( QString &destination, QString &providerKey, QString &uri, QString &layerName, QString &format, QMap<QString, QVariant> &options, bool &useWriter );

Expand Down

0 comments on commit 4103614

Please sign in to comment.