Skip to content

Commit

Permalink
feat: New force read only option for vector layer
Browse files Browse the repository at this point in the history
To be able to open vector layer in a read-only mode, a new vector layer option has been defined to do it.

This option is used to open world_map.gpkg and fixes #35383
  • Loading branch information
rldhont authored and nyalldawson committed Sep 11, 2022
1 parent 0fc64b1 commit c26d58e
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 9 deletions.
6 changes: 5 additions & 1 deletion python/core/auto_generated/vector/qgsvectorlayer.sip.in
Expand Up @@ -1842,7 +1842,9 @@ If you need only the count of committed features call this method on this layer'
%Docstring
Makes layer read-only (editing disabled) or not

:return: ``False`` if the layer is in editing yet
:return: ``False`` if the layer is in editing yet or if the data source is in read-only mode

.. seealso:: :py:func:`readOnlyChanged`
%End

virtual bool supportsEditing() const;
Expand Down Expand Up @@ -3015,6 +3017,8 @@ Will be emitted whenever the edit form configuration of this layer changes.
Emitted when the read only state of this layer is changed.
Only applies to manually set readonly state, not to the edit mode.

.. seealso:: :py:func:`setReadOnly`

.. versionadded:: 3.0
%End

Expand Down
4 changes: 2 additions & 2 deletions src/app/qgsstatusbarcoordinateswidget.cpp
Expand Up @@ -255,7 +255,8 @@ void QgsStatusBarCoordinatesWidget::world()
}
const QString fileName = QgsApplication::pkgDataPath() + QStringLiteral( "/resources/data/world_map.gpkg|layername=countries" );
const QFileInfo fileInfo = QFileInfo( fileName );
const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
options.forceReadOnly = true;
QgsVectorLayer *layer = new QgsVectorLayer( fileInfo.absoluteFilePath(),
tr( "World Map" ), QStringLiteral( "ogr" ), options );
// Register this layer with the layers registry
Expand Down Expand Up @@ -384,4 +385,3 @@ void QgsStatusBarCoordinatesWidget::ensureCoordinatesVisible()
mLineEdit->setMaximumWidth( width );
}
}

14 changes: 12 additions & 2 deletions src/core/vector/qgsvectorlayer.cpp
Expand Up @@ -189,6 +189,7 @@ QgsVectorLayer::QgsVectorLayer( const QString &vectorLayerPath,
if ( options.forceReadOnly )
{
providerFlags |= QgsDataProvider::ForceReadOnly;
mDataSourceReadOnly = true;
}
setDataSource( vectorLayerPath, baseName, providerKey, providerOptions, providerFlags );
}
Expand Down Expand Up @@ -272,6 +273,7 @@ QgsVectorLayer *QgsVectorLayer::clone() const
{
dataSource = source();
}
options.forceReadOnly = mDataSourceReadOnly;
QgsVectorLayer *layer = new QgsVectorLayer( dataSource, name(), mProviderKey, options );
if ( mDataProvider && layer->dataProvider() )
{
Expand Down Expand Up @@ -1573,6 +1575,7 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
mProviderKey = QStringLiteral( "ogr" );
}

const QDomElement elem = layer_node.toElement();
QgsDataProvider::ProviderOptions options { context.transformContext() };
QgsDataProvider::ReadFlags flags;
if ( mReadFlags & QgsMapLayer::FlagTrustLayerMetadata )
Expand All @@ -1585,7 +1588,6 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
{
QgsDebugMsg( QStringLiteral( "Could not set data provider for layer %1" ).arg( publicSource() ) );
}
const QDomElement elem = layer_node.toElement();

// for invalid layer sources, we fallback to stored wkbType if available
if ( elem.hasAttribute( QStringLiteral( "wkbType" ) ) )
Expand All @@ -1594,6 +1596,7 @@ bool QgsVectorLayer::readXml( const QDomNode &layer_node, QgsReadWriteContext &c
if ( mReadFlags & QgsMapLayer::FlagForceReadOnly )
{
flags |= QgsDataProvider::ForceReadOnly;
mDataSourceReadOnly = true;
}

QDomElement pkeyElem = pkeyNode.toElement();
Expand Down Expand Up @@ -3750,7 +3753,7 @@ bool QgsVectorLayer::isSpatial() const

bool QgsVectorLayer::isReadOnly() const
{
return mReadOnly;
return mDataSourceReadOnly || mReadOnly;
}

bool QgsVectorLayer::setReadOnly( bool readonly )
Expand All @@ -3759,6 +3762,10 @@ bool QgsVectorLayer::setReadOnly( bool readonly )
if ( readonly && mEditBuffer )
return false;

// exit if the data source is in read-only mode
if ( !readonly && mDataSourceReadOnly )
return false;

mReadOnly = readonly;
emit readOnlyChanged();
return true;
Expand All @@ -3769,6 +3776,9 @@ bool QgsVectorLayer::supportsEditing() const
if ( ! mDataProvider )
return false;

if ( mDataSourceReadOnly )
return false;

return mDataProvider->capabilities() & QgsVectorDataProvider::EditingCapabilities && ! mReadOnly;
}

Expand Down
36 changes: 33 additions & 3 deletions src/core/vector/qgsvectorlayer.h
Expand Up @@ -486,6 +486,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
*/
bool skipCrsValidation = false;

/**
* Controls whether the layer is forced to be load as Read Only
*
* If TRUE, then the layer's provider will only check read capabilities.
* Write capabilities will be skipped.
*
* If FALSE (the default), the layer's provider will check the
* edition capabilities based on user rights or file rights or
* others.
* \since QGIS 3.28
*/
bool forceReadOnly = false;
};

/**
Expand Down Expand Up @@ -1725,7 +1737,9 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte

/**
* Makes layer read-only (editing disabled) or not
* \returns FALSE if the layer is in editing yet
* \returns FALSE if the layer is in editing yet or if the data source is in read-only mode
*
* \see readOnlyChanged()
*/
bool setReadOnly( bool readonly = true );

Expand Down Expand Up @@ -2792,6 +2806,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
* Emitted when the read only state of this layer is changed.
* Only applies to manually set readonly state, not to the edit mode.
*
* \see setReadOnly()
*
* \since QGIS 3.0
*/
void readOnlyChanged();
Expand Down Expand Up @@ -2830,7 +2846,13 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
void updateDefaultValues( QgsFeatureId fid, QgsFeature feature = QgsFeature() );

/**
* Returns TRUE if the provider is in read-only mode
* Returns TRUE if the layer is in read-only mode
*
* \note the layer can be in read-only mode by construction or by action
* \see QgsVectorLayer::LayerOptions.forceReadOnly
* \see QgsMapLayer::FlagForceReadOnly
* \see setReadOnly()
* \see readOnlyChanged()
*/
bool isReadOnly() const FINAL;

Expand Down Expand Up @@ -2893,7 +2915,15 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer, public QgsExpressionConte
//! The user-defined actions that are accessed from the Identify Results dialog box
QgsActionManager *mActions = nullptr;

//! Flag indicating whether the layer is in read-only mode (editing disabled) or not
//! Flag indicating whether the layer has been created in read-only mode (editing disabled) or not
bool mDataSourceReadOnly = false;

/**
* Flag indicating whether the layer has been converted in read-only mode (editing disabled) or not
* \see setReadOnly()
* \see readOnlyChanged()
* \see isReadOnly()
*/
bool mReadOnly = false;

/**
Expand Down
4 changes: 3 additions & 1 deletion src/gui/qgscoordinateboundspreviewmapwidget.cpp
Expand Up @@ -35,7 +35,9 @@ QgsCoordinateBoundsPreviewMapWidget::QgsCoordinateBoundsPreviewMapWidget( QWidge
setDestinationCrs( srs );

const QString layerPath = QgsApplication::pkgDataPath() + QStringLiteral( "/resources/data/world_map.gpkg|layername=countries" );
mLayers << new QgsVectorLayer( layerPath );
QgsVectorLayer::LayerOptions options;
options.forceReadOnly = true;
mLayers << new QgsVectorLayer( layerPath, tr( "World Map" ), QStringLiteral( "ogr" ), options );
setLayers( mLayers );
mPanTool = new QgsMapToolPan( this );
setMapTool( mPanTool );
Expand Down

0 comments on commit c26d58e

Please sign in to comment.