mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
[api] Add API to indicate that individual layers may be loaded without any
CRS validation, regardless of the user's settings This avoids hacks put in place in other parts of QGIS code or in plugins to temporarily deactivate the CRS validation prompt, providing a supported, stable method to indicate that when loading a particular layer no CRS validation is required.
This commit is contained in:
parent
71ddea9bd2
commit
cb06519d16
@ -88,6 +88,8 @@ Constructor for LayerOptions with optional ``transformContext``.
|
||||
%End
|
||||
|
||||
QgsCoordinateTransformContext transformContext;
|
||||
|
||||
bool allowInvalidCrs;
|
||||
};
|
||||
|
||||
explicit QgsMeshLayer( const QString &path = QString(), const QString &baseName = QString(), const QString &providerLib = QStringLiteral( "mesh_memory" ),
|
||||
|
@ -1679,6 +1679,7 @@ this method is now deprecated and always return false, because circular dependen
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
QFlags<QgsMapLayer::LayerFlag> operator|(QgsMapLayer::LayerFlag f1, QFlags<QgsMapLayer::LayerFlag> f2);
|
||||
|
@ -352,6 +352,8 @@ Constructor for LayerOptions.
|
||||
|
||||
QgsCoordinateReferenceSystem fallbackCrs;
|
||||
|
||||
bool allowInvalidCrs;
|
||||
|
||||
};
|
||||
|
||||
explicit QgsVectorLayer( const QString &path = QString(), const QString &baseName = QString(),
|
||||
|
@ -114,6 +114,8 @@ Constructor for LayerOptions.
|
||||
|
||||
QgsCoordinateTransformContext transformContext;
|
||||
|
||||
bool allowInvalidCrs;
|
||||
|
||||
};
|
||||
|
||||
explicit QgsRasterLayer( const QString &uri,
|
||||
|
@ -113,16 +113,14 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
|
||||
|
||||
if fileName is None:
|
||||
return
|
||||
prjSetting = None
|
||||
settings = QgsSettings()
|
||||
if crs is not None:
|
||||
prjSetting = settings.value('/Projections/defaultBehavior')
|
||||
settings.setValue('/Projections/defaultBehavior', '')
|
||||
|
||||
if name is None:
|
||||
name = os.path.split(fileName)[1]
|
||||
|
||||
if isRaster:
|
||||
qgslayer = QgsRasterLayer(fileName, name)
|
||||
options = QgsRasterLayer.LayerOptions()
|
||||
options.allowInvalidCrs = True
|
||||
qgslayer = QgsRasterLayer(fileName, name, 'gdal', options)
|
||||
if qgslayer.isValid():
|
||||
if crs is not None and qgslayer.crs() is None:
|
||||
qgslayer.setCrs(crs, False)
|
||||
@ -131,13 +129,13 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
|
||||
qgslayer.loadNamedStyle(style)
|
||||
QgsProject.instance().addMapLayers([qgslayer])
|
||||
else:
|
||||
if prjSetting:
|
||||
settings.setValue('/Projections/defaultBehavior', prjSetting)
|
||||
raise RuntimeError(QCoreApplication.translate('dataobject',
|
||||
'Could not load layer: {0}\nCheck the processing framework log to look for errors.').format(
|
||||
fileName))
|
||||
else:
|
||||
qgslayer = QgsVectorLayer(fileName, name, 'ogr')
|
||||
options = QgsVectorLayer.LayerOptions()
|
||||
options.allowInvalidCrs = True
|
||||
qgslayer = QgsVectorLayer(fileName, name, 'ogr', options)
|
||||
if qgslayer.isValid():
|
||||
if crs is not None and qgslayer.crs() is None:
|
||||
qgslayer.setCrs(crs, False)
|
||||
@ -151,9 +149,6 @@ def load(fileName, name=None, crs=None, style=None, isRaster=False):
|
||||
qgslayer.loadNamedStyle(style)
|
||||
QgsProject.instance().addMapLayers([qgslayer])
|
||||
|
||||
if prjSetting:
|
||||
settings.setValue('/Projections/defaultBehavior', prjSetting)
|
||||
|
||||
return qgslayer
|
||||
|
||||
|
||||
|
@ -42,6 +42,8 @@ QgsMeshLayer::QgsMeshLayer( const QString &meshLayerPath,
|
||||
const QgsMeshLayer::LayerOptions &options )
|
||||
: QgsMapLayer( QgsMapLayerType::MeshLayer, baseName, meshLayerPath )
|
||||
{
|
||||
mShouldValidateCrs = !options.allowInvalidCrs;
|
||||
|
||||
setProviderType( providerKey );
|
||||
// if we’re given a provider type, try to create and bind one to this layer
|
||||
if ( !meshLayerPath.isEmpty() && !providerKey.isEmpty() )
|
||||
|
@ -107,6 +107,21 @@ class CORE_EXPORT QgsMeshLayer : public QgsMapLayer
|
||||
{}
|
||||
|
||||
QgsCoordinateTransformContext transformContext;
|
||||
|
||||
/**
|
||||
* Controls whether the layer is allowed to have an invalid/unknown CRS.
|
||||
*
|
||||
* If TRUE, then no validation will be performed on the layer's CRS and the layer
|
||||
* layer's crs() may be invalid() (i.e. the layer will have no georeferencing available
|
||||
* and will be treated as having purely numerical coordinates).
|
||||
*
|
||||
* If FALSE (the default), the layer's CRS will be validated using QgsCoordinateReferenceSystem::validate(),
|
||||
* which may cause a blocking, user-facing dialog asking users to manually select the correct CRS for the
|
||||
* layer.
|
||||
*
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
bool allowInvalidCrs = false;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -193,28 +193,6 @@ QgsMapLayer *QgsProcessingUtils::mapLayerFromStore( const QString &string, QgsMa
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///@cond PRIVATE
|
||||
class ProjectionSettingRestorer
|
||||
{
|
||||
public:
|
||||
|
||||
ProjectionSettingRestorer()
|
||||
{
|
||||
QgsSettings settings;
|
||||
previousSetting = settings.value( QStringLiteral( "/Projections/defaultBehavior" ) ).toString();
|
||||
settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), QStringLiteral( "useProject" ) );
|
||||
}
|
||||
|
||||
~ProjectionSettingRestorer()
|
||||
{
|
||||
QgsSettings settings;
|
||||
settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), previousSetting );
|
||||
}
|
||||
|
||||
QString previousSetting;
|
||||
};
|
||||
///@endcond PRIVATE
|
||||
|
||||
QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string, const QgsCoordinateTransformContext &transformContext, LayerHint typeHint )
|
||||
{
|
||||
QStringList components = string.split( '|' );
|
||||
@ -229,10 +207,6 @@ QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string,
|
||||
else
|
||||
return nullptr;
|
||||
|
||||
// TODO - remove when there is a cleaner way to block the unknown projection dialog!
|
||||
ProjectionSettingRestorer restorer;
|
||||
( void )restorer; // no warnings
|
||||
|
||||
QString name = fi.baseName();
|
||||
|
||||
// brute force attempt to load a matching layer
|
||||
@ -240,6 +214,7 @@ QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string,
|
||||
{
|
||||
QgsVectorLayer::LayerOptions options { transformContext };
|
||||
options.loadDefaultStyle = false;
|
||||
options.allowInvalidCrs = true;
|
||||
std::unique_ptr< QgsVectorLayer > layer = qgis::make_unique<QgsVectorLayer>( string, name, QStringLiteral( "ogr" ), options );
|
||||
if ( layer->isValid() )
|
||||
{
|
||||
@ -250,6 +225,7 @@ QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string,
|
||||
{
|
||||
QgsRasterLayer::LayerOptions rasterOptions;
|
||||
rasterOptions.loadDefaultStyle = false;
|
||||
rasterOptions.allowInvalidCrs = true;
|
||||
std::unique_ptr< QgsRasterLayer > rasterLayer( new QgsRasterLayer( string, name, QStringLiteral( "gdal" ), rasterOptions ) );
|
||||
if ( rasterLayer->isValid() )
|
||||
{
|
||||
@ -259,6 +235,7 @@ QgsMapLayer *QgsProcessingUtils::loadMapLayerFromString( const QString &string,
|
||||
if ( typeHint == LayerHint::UnknownType || typeHint == LayerHint::Mesh )
|
||||
{
|
||||
QgsMeshLayer::LayerOptions meshOptions;
|
||||
meshOptions.allowInvalidCrs = true;
|
||||
std::unique_ptr< QgsMeshLayer > meshLayer( new QgsMeshLayer( string, name, QStringLiteral( "mdal" ), meshOptions ) );
|
||||
if ( meshLayer->isValid() )
|
||||
{
|
||||
|
@ -74,5 +74,7 @@ QgsVectorLayer *QgsMemoryProviderUtils::createMemoryLayer( const QString &name,
|
||||
}
|
||||
|
||||
QString uri = geomType + '?' + parts.join( '&' );
|
||||
return new QgsVectorLayer( uri, name, QStringLiteral( "memory" ), QgsVectorLayer::LayerOptions( QgsCoordinateTransformContext() ) );
|
||||
QgsVectorLayer::LayerOptions options{ QgsCoordinateTransformContext() };
|
||||
options.allowInvalidCrs = true;
|
||||
return new QgsVectorLayer( uri, name, QStringLiteral( "memory" ), options );
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ void QgsMapLayer::clone( QgsMapLayer *layer ) const
|
||||
layer->setLegendUrl( legendUrl() );
|
||||
layer->setLegendUrlFormat( legendUrlFormat() );
|
||||
layer->setDependencies( dependencies() );
|
||||
layer->mShouldValidateCrs = mShouldValidateCrs;
|
||||
layer->setCrs( crs() );
|
||||
layer->setCustomProperties( mCustomProperties );
|
||||
}
|
||||
@ -764,7 +765,7 @@ void QgsMapLayer::setCrs( const QgsCoordinateReferenceSystem &srs, bool emitSign
|
||||
{
|
||||
mCRS = srs;
|
||||
|
||||
if ( isSpatial() && !mCRS.isValid() )
|
||||
if ( mShouldValidateCrs && isSpatial() && !mCRS.isValid() )
|
||||
{
|
||||
mCRS.setValidationHint( tr( "Specify CRS for layer %1" ).arg( name() ) );
|
||||
mCRS.validate();
|
||||
|
@ -1533,6 +1533,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
//! Read flags. It's up to the subclass to respect these when restoring state from XML
|
||||
QgsMapLayer::ReadFlags mReadFlags = nullptr;
|
||||
|
||||
/**
|
||||
* TRUE if the layer's CRS should be validated and invalid CRSes are not permitted.
|
||||
*
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
bool mShouldValidateCrs = true;
|
||||
|
||||
private:
|
||||
|
||||
virtual QString baseURI( PropertyType type ) const;
|
||||
|
@ -150,6 +150,8 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
|
||||
, mAuxiliaryLayerKey( QString() )
|
||||
, mReadExtentFromXml( options.readExtentFromXml )
|
||||
{
|
||||
mShouldValidateCrs = !options.allowInvalidCrs;
|
||||
|
||||
if ( options.fallbackCrs.isValid() )
|
||||
setCrs( options.fallbackCrs, false );
|
||||
mWkbType = options.fallbackWkbType;
|
||||
|
@ -465,6 +465,21 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
|
||||
*/
|
||||
QgsCoordinateReferenceSystem fallbackCrs;
|
||||
|
||||
/**
|
||||
* Controls whether the layer is allowed to have an invalid/unknown CRS.
|
||||
*
|
||||
* If TRUE, then no validation will be performed on the layer's CRS and the layer
|
||||
* layer's crs() may be invalid() (i.e. the layer will have no georeferencing available
|
||||
* and will be treated as having purely numerical coordinates).
|
||||
*
|
||||
* If FALSE (the default), the layer's CRS will be validated using QgsCoordinateReferenceSystem::validate(),
|
||||
* which may cause a blocking, user-facing dialog asking users to manually select the correct CRS for the
|
||||
* layer.
|
||||
*
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
bool allowInvalidCrs = false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -117,6 +117,8 @@ QgsRasterLayer::QgsRasterLayer( const QString &uri,
|
||||
, QSTRING_NOT_SET( QStringLiteral( "Not Set" ) )
|
||||
, TRSTRING_NOT_SET( tr( "Not Set" ) )
|
||||
{
|
||||
mShouldValidateCrs = !options.allowInvalidCrs;
|
||||
|
||||
QgsDebugMsgLevel( QStringLiteral( "Entered" ), 4 );
|
||||
setProviderType( providerKey );
|
||||
|
||||
|
@ -188,6 +188,21 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
|
||||
*/
|
||||
QgsCoordinateTransformContext transformContext = QgsCoordinateTransformContext();
|
||||
|
||||
/**
|
||||
* Controls whether the layer is allowed to have an invalid/unknown CRS.
|
||||
*
|
||||
* If TRUE, then no validation will be performed on the layer's CRS and the layer
|
||||
* layer's crs() may be invalid() (i.e. the layer will have no georeferencing available
|
||||
* and will be treated as having purely numerical coordinates).
|
||||
*
|
||||
* If FALSE (the default), the layer's CRS will be validated using QgsCoordinateReferenceSystem::validate(),
|
||||
* which may cause a blocking, user-facing dialog asking users to manually select the correct CRS for the
|
||||
* layer.
|
||||
*
|
||||
* \since QGIS 3.10
|
||||
*/
|
||||
bool allowInvalidCrs = false;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -161,26 +161,6 @@ QgsBrowserLayerProperties::QgsBrowserLayerProperties( QWidget *parent )
|
||||
} );
|
||||
}
|
||||
|
||||
class ProjectionSettingRestorer
|
||||
{
|
||||
public:
|
||||
|
||||
ProjectionSettingRestorer()
|
||||
{
|
||||
QgsSettings settings;
|
||||
previousSetting = settings.value( QStringLiteral( "/Projections/defaultBehavior" ) ).toString();
|
||||
settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), QStringLiteral( "useProject" ) );
|
||||
}
|
||||
|
||||
~ProjectionSettingRestorer()
|
||||
{
|
||||
QgsSettings settings;
|
||||
settings.setValue( QStringLiteral( "/Projections/defaultBehavior" ), previousSetting );
|
||||
}
|
||||
|
||||
QString previousSetting;
|
||||
};
|
||||
|
||||
void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
{
|
||||
QgsLayerItem *layerItem = qobject_cast<QgsLayerItem *>( item );
|
||||
@ -191,13 +171,6 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
|
||||
QgsMapLayerType type = layerItem->mapLayerType();
|
||||
QString layerMetadata = tr( "Error" );
|
||||
QgsCoordinateReferenceSystem layerCrs;
|
||||
|
||||
QString defaultProjectionOption = QgsSettings().value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString();
|
||||
// temporarily override /Projections/defaultBehavior to avoid dialog prompt
|
||||
// TODO - remove when there is a cleaner way to block the unknown projection dialog!
|
||||
ProjectionSettingRestorer restorer;
|
||||
( void )restorer; // no warnings
|
||||
|
||||
mLayer.reset();
|
||||
|
||||
@ -211,14 +184,17 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "creating raster layer" ) );
|
||||
// should copy code from addLayer() to split uri ?
|
||||
mLayer = qgis::make_unique< QgsRasterLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey() );
|
||||
QgsRasterLayer::LayerOptions options;
|
||||
options.allowInvalidCrs = true;
|
||||
mLayer = qgis::make_unique< QgsRasterLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
|
||||
break;
|
||||
}
|
||||
|
||||
case QgsMapLayerType::MeshLayer:
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "creating mesh layer" ) );
|
||||
const QgsMeshLayer::LayerOptions options { QgsProject::instance()->transformContext() };
|
||||
QgsMeshLayer::LayerOptions options { QgsProject::instance()->transformContext() };
|
||||
options.allowInvalidCrs = true;
|
||||
mLayer = qgis::make_unique < QgsMeshLayer >( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
|
||||
break;
|
||||
}
|
||||
@ -226,7 +202,8 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
case QgsMapLayerType::VectorLayer:
|
||||
{
|
||||
QgsDebugMsg( QStringLiteral( "creating vector layer" ) );
|
||||
const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
|
||||
QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
|
||||
options.allowInvalidCrs = true;
|
||||
mLayer = qgis::make_unique < QgsVectorLayer>( layerItem->uri(), layerItem->name(), layerItem->providerKey(), options );
|
||||
break;
|
||||
}
|
||||
@ -249,7 +226,6 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
{
|
||||
bool ok = false;
|
||||
mLayer->loadDefaultMetadata( ok );
|
||||
layerCrs = mLayer->crs();
|
||||
layerMetadata = mLayer->htmlMetadata();
|
||||
|
||||
mMapCanvas->setDestinationCrs( mLayer->crs() );
|
||||
@ -267,15 +243,6 @@ void QgsBrowserLayerProperties::setItem( QgsDataItem *item )
|
||||
mMetadataTextBrowser->document()->setDefaultStyleSheet( myStyle );
|
||||
mMetadataTextBrowser->setHtml( layerMetadata );
|
||||
|
||||
// report if layer was set to to project crs without prompt (may give a false positive)
|
||||
if ( defaultProjectionOption == QLatin1String( "prompt" ) )
|
||||
{
|
||||
QgsCoordinateReferenceSystem defaultCrs =
|
||||
QgsProject::instance()->crs();
|
||||
if ( layerCrs == defaultCrs )
|
||||
mNoticeLabel->setText( "NOTICE: Layer CRS set from project (" + defaultCrs.authid() + ')' );
|
||||
}
|
||||
|
||||
if ( mNoticeLabel->text().isEmpty() )
|
||||
{
|
||||
mNoticeLabel->hide();
|
||||
|
@ -302,22 +302,10 @@ QString QgsRasterFormatSaveOptionsWidget::validateOptions( bool gui, bool report
|
||||
bool tmpLayer = false;
|
||||
if ( !( mRasterLayer && rasterLayer->dataProvider() ) && ! mRasterFileName.isNull() )
|
||||
{
|
||||
// temporarily override /Projections/defaultBehavior to avoid dialog prompt
|
||||
// this is taken from qgsbrowserdockwidget.cpp
|
||||
// TODO - integrate this into qgis core
|
||||
QgsSettings settings;
|
||||
QString defaultProjectionOption = settings.value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString();
|
||||
if ( settings.value( QStringLiteral( "Projections/defaultBehavior" ), "prompt" ).toString() == QLatin1String( "prompt" ) )
|
||||
{
|
||||
settings.setValue( QStringLiteral( "Projections/defaultBehavior" ), "useProject" );
|
||||
}
|
||||
tmpLayer = true;
|
||||
rasterLayer = new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), QStringLiteral( "gdal" ) );
|
||||
// restore /Projections/defaultBehavior
|
||||
if ( defaultProjectionOption == QLatin1String( "prompt" ) )
|
||||
{
|
||||
settings.setValue( QStringLiteral( "Projections/defaultBehavior" ), defaultProjectionOption );
|
||||
}
|
||||
QgsRasterLayer::LayerOptions options;
|
||||
options.allowInvalidCrs = true;
|
||||
rasterLayer = new QgsRasterLayer( mRasterFileName, QFileInfo( mRasterFileName ).baseName(), QStringLiteral( "gdal" ), options );
|
||||
}
|
||||
|
||||
if ( mProvider == QLatin1String( "gdal" ) && mPyramids )
|
||||
|
Loading…
x
Reference in New Issue
Block a user