Skip to content

Commit 05953cb

Browse files
committed
[BUGFIX / FEATURE] [OGR] Allow concurrent edition of Shapefiles and Tabfiles in QGIS & MapInfo
- Closes https://hub.qgis.org/issues/14378 - Adds new virtual methods in QgsDataProvider(): enterUpdateMode() and leaveUpdateMode() and implement them in the OGR provider. Limited to shapefiles and tabfiles - Implements QgsOGRProvider:reloadData() - Robustify OGR provider methods so they don't crash if dataset re-opening fails. Cherry picked from dc18b5b
1 parent 5a00172 commit 05953cb

10 files changed

+631
-30
lines changed

python/core/qgsdataprovider.sip

+41
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,47 @@ class QgsDataProvider : QObject
223223
*/
224224
virtual void invalidateConnections( const QString& connection );
225225

226+
/** Enter update mode.
227+
*
228+
* This is aimed at providers that can open differently the connection to
229+
* the datasource, according it to be in update mode or in read-only mode.
230+
* A call to this method shall be balanced with a call to leaveUpdateMode(),
231+
* if this method returns true.
232+
*
233+
* Most providers will have an empty implementation for that method.
234+
*
235+
* For backward compatibility, providers that implement enterUpdateMode() should
236+
* still make sure to allow editing operations to work even if enterUpdateMode()
237+
* is not explicitly called.
238+
*
239+
* Several successive calls to enterUpdateMode() can be done. So there is
240+
* a concept of stack of calls that must be handled by the provider. Only the first
241+
* call to enterUpdateMode() will really turn update mode on.
242+
*
243+
* @return true in case of success (or no-op implementation), false in case of failure
244+
*
245+
* @note added in QGIS 2.16
246+
*/
247+
virtual bool enterUpdateMode();
248+
249+
/** Leave update mode.
250+
*
251+
* This is aimed at providers that can open differently the connection to
252+
* the datasource, according it to be in update mode or in read-only mode.
253+
* This method shall be balanced with a succesful call to enterUpdateMode().
254+
*
255+
* Most providers will have an empty implementation for that method.
256+
*
257+
* Several successive calls to enterUpdateMode() can be done. So there is
258+
* a concept of stack of calls that must be handled by the provider. Only the last
259+
* call to leaveUpdateMode() will really turn update mode off.
260+
*
261+
* @return true in case of success (or no-op implementation), false in case of failure
262+
*
263+
* @note added in QGIS 2.16
264+
*/
265+
virtual bool leaveUpdateMode();
266+
226267
signals:
227268

228269
/**

src/core/qgsdataprovider.h

+41
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,47 @@ class CORE_EXPORT QgsDataProvider : public QObject
311311
*/
312312
virtual void invalidateConnections( const QString& connection ) { Q_UNUSED( connection ); }
313313

314+
/** Enter update mode.
315+
*
316+
* This is aimed at providers that can open differently the connection to
317+
* the datasource, according it to be in update mode or in read-only mode.
318+
* A call to this method shall be balanced with a call to leaveUpdateMode(),
319+
* if this method returns true.
320+
*
321+
* Most providers will have an empty implementation for that method.
322+
*
323+
* For backward compatibility, providers that implement enterUpdateMode() should
324+
* still make sure to allow editing operations to work even if enterUpdateMode()
325+
* is not explicitly called.
326+
*
327+
* Several successive calls to enterUpdateMode() can be done. So there is
328+
* a concept of stack of calls that must be handled by the provider. Only the first
329+
* call to enterUpdateMode() will really turn update mode on.
330+
*
331+
* @return true in case of success (or no-op implementation), false in case of failure.
332+
*
333+
* @note added in QGIS 2.16
334+
*/
335+
virtual bool enterUpdateMode() { return true; }
336+
337+
/** Leave update mode.
338+
*
339+
* This is aimed at providers that can open differently the connection to
340+
* the datasource, according it to be in update mode or in read-only mode.
341+
* This method shall be balanced with a succesful call to enterUpdateMode().
342+
*
343+
* Most providers will have an empty implementation for that method.
344+
*
345+
* Several successive calls to enterUpdateMode() can be done. So there is
346+
* a concept of stack of calls that must be handled by the provider. Only the last
347+
* call to leaveUpdateMode() will really turn update mode off.
348+
*
349+
* @return true in case of success (or no-op implementation), false in case of failure.
350+
*
351+
* @note added in QGIS 2.16
352+
*/
353+
virtual bool leaveUpdateMode() { return true; }
354+
314355
signals:
315356

316357
/**

src/core/qgsvectorlayer.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,7 @@ void QgsVectorLayer::reload()
379379
if ( mDataProvider )
380380
{
381381
mDataProvider->reloadData();
382+
updateFields();
382383
}
383384
}
384385

@@ -1380,6 +1381,8 @@ bool QgsVectorLayer::startEditing()
13801381

13811382
emit beforeEditingStarted();
13821383

1384+
mDataProvider->enterUpdateMode();
1385+
13831386
if ( mDataProvider->transaction() )
13841387
{
13851388
mEditBuffer = new QgsVectorLayerEditPassthrough( this );
@@ -2334,6 +2337,8 @@ bool QgsVectorLayer::commitChanges()
23342337
updateFields();
23352338
mDataProvider->updateExtents();
23362339

2340+
mDataProvider->leaveUpdateMode();
2341+
23372342
emit repaintRequested();
23382343

23392344
return success;
@@ -2384,6 +2389,8 @@ bool QgsVectorLayer::rollBack( bool deleteBuffer )
23842389
if ( rollbackExtent )
23852390
updateExtents();
23862391

2392+
mDataProvider->leaveUpdateMode();
2393+
23872394
emit repaintRequested();
23882395
return true;
23892396
}

src/providers/ogr/qgsogrfeatureiterator.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
4444
mFeatureFetched = false;
4545

4646
mConn = QgsOgrConnPool::instance()->acquireConnection( mSource->mProvider->dataSourceUri() );
47+
if ( mConn->ds == nullptr )
48+
{
49+
return;
50+
}
4751

4852
if ( mSource->mLayerName.isNull() )
4953
{
@@ -53,10 +57,18 @@ QgsOgrFeatureIterator::QgsOgrFeatureIterator( QgsOgrFeatureSource* source, bool
5357
{
5458
ogrLayer = OGR_DS_GetLayerByName( mConn->ds, TO8( mSource->mLayerName ) );
5559
}
60+
if ( ogrLayer == nullptr )
61+
{
62+
return;
63+
}
5664

5765
if ( !mSource->mSubsetString.isEmpty() )
5866
{
5967
ogrLayer = QgsOgrUtils::setSubsetString( ogrLayer, mConn->ds, mSource->mEncoding, mSource->mSubsetString );
68+
if ( ogrLayer == nullptr )
69+
{
70+
return;
71+
}
6072
mSubsetStringSet = true;
6173
}
6274

@@ -204,7 +216,7 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
204216
{
205217
feature.setValid( false );
206218

207-
if ( mClosed )
219+
if ( mClosed || ogrLayer == nullptr )
208220
return false;
209221

210222
if ( mRequest.filterType() == QgsFeatureRequest::FilterFid )
@@ -249,7 +261,7 @@ bool QgsOgrFeatureIterator::fetchFeature( QgsFeature& feature )
249261

250262
bool QgsOgrFeatureIterator::rewind()
251263
{
252-
if ( mClosed )
264+
if ( mClosed || ogrLayer == nullptr )
253265
return false;
254266

255267
OGR_L_ResetReading( ogrLayer );

0 commit comments

Comments
 (0)