Skip to content

Commit 7d7cdcd

Browse files
committed
Repack shapefiles when saving after deleting features
* QgsVectorDataProvider::dataChanged() will be emitted * QgsVectorLayer::dataChanged() will be emitted * Clears QgsVectorLayerCache * Reloads the attribute table * Clears the selection Looking forward to people complaining about their lost selection... Fix #10560 Fix #11989 Refs #8317 Refs #8822 Refs #10483 Refs #11007 Refs #7540 Refs #11398 Refs #11296
1 parent a39ea34 commit 7d7cdcd

12 files changed

+118
-77
lines changed

src/core/qgsdataprovider.h

+3
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ class CORE_EXPORT QgsDataProvider : public QObject
308308
/**
309309
* This is emitted whenever an asynchronous operation has finished
310310
* and the data should be redrawn
311+
*
312+
* When emitted from a QgsVectorDataProvider, any cached information such as
313+
* feature ids should be invalidated.
311314
*/
312315
void dataChanged();
313316

src/core/qgsvectorlayer.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1366,6 +1366,7 @@ bool QgsVectorLayer::setDataProvider( QString const & provider )
13661366
{
13671367
// XXX should I check for and possibly delete any pre-existing providers?
13681368
// XXX How often will that scenario occur?
1369+
Q_ASSERT( !mDataProvider );
13691370

13701371
mProviderKey = provider; // XXX is this necessary? Usually already set
13711372
// XXX when execution gets here.
@@ -1457,6 +1458,8 @@ bool QgsVectorLayer::setDataProvider( QString const & provider )
14571458
return false;
14581459
}
14591460

1461+
connect( mDataProvider, SIGNAL( dataChanged() ), this, SIGNAL( dataChanged() ) );
1462+
connect( mDataProvider, SIGNAL( dataChanged() ), this, SLOT( removeSelection() ) );
14601463
return true;
14611464

14621465
} // QgsVectorLayer:: setDataProvider

src/core/qgsvectorlayer.h

-1
Original file line numberDiff line numberDiff line change
@@ -1753,7 +1753,6 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
17531753
*/
17541754
void writeCustomSymbology( QDomElement& element, QDomDocument& doc, QString& errorMessage ) const;
17551755

1756-
17571756
private slots:
17581757
void onRelationsLoaded();
17591758
void onJoinedFieldsChanged();

src/core/qgsvectorlayercache.cpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ QgsVectorLayerCache::QgsVectorLayerCache( QgsVectorLayer* layer, int cacheSize,
3535
setCacheAddedAttributes( true );
3636

3737
connect( mLayer, SIGNAL( attributeDeleted( int ) ), SLOT( attributeDeleted( int ) ) );
38-
connect( mLayer, SIGNAL( updatedFields() ), SLOT( updatedFields() ) );
38+
connect( mLayer, SIGNAL( updatedFields() ), SLOT( invalidate() ) );
39+
connect( mLayer, SIGNAL( dataChanged() ), SLOT( invalidate() ) );
3940
connect( mLayer, SIGNAL( attributeValueChanged( QgsFeatureId, int, const QVariant& ) ), SLOT( onAttributeValueChanged( QgsFeatureId, int, const QVariant& ) ) );
4041
}
4142

@@ -231,9 +232,15 @@ void QgsVectorLayerCache::attributeAdded( int field )
231232

232233
void QgsVectorLayerCache::attributeDeleted( int field )
233234
{
234-
foreach ( QgsFeatureId fid, mCache.keys() )
235+
QgsAttributeList attrs = mCachedAttributes;
236+
mCachedAttributes.clear();
237+
238+
Q_FOREACH ( int attr, attrs )
235239
{
236-
mCache[ fid ]->mFeature->deleteAttribute( field );
240+
if ( attr < field )
241+
mCachedAttributes << attr;
242+
else if ( attr > field )
243+
mCachedAttributes << attr - 1;
237244
}
238245
}
239246

@@ -253,9 +260,10 @@ void QgsVectorLayerCache::layerDeleted()
253260
mLayer = NULL;
254261
}
255262

256-
void QgsVectorLayerCache::updatedFields()
263+
void QgsVectorLayerCache::invalidate()
257264
{
258265
mCache.clear();
266+
emit invalidated();
259267
}
260268

261269
QgsFeatureIterator QgsVectorLayerCache::getFeatures( const QgsFeatureRequest &featureRequest )

src/core/qgsvectorlayercache.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,11 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
256256
*/
257257
void featureAdded( QgsFeatureId fid );
258258

259+
/**
260+
* The cache has been invalidated and cleared.
261+
*/
262+
void invalidated();
263+
259264
private slots:
260265
void onAttributeValueChanged( QgsFeatureId fid, int field, const QVariant& value );
261266
void featureDeleted( QgsFeatureId fid );
@@ -264,7 +269,7 @@ class CORE_EXPORT QgsVectorLayerCache : public QObject
264269
void attributeDeleted( int field );
265270
void geometryChanged( QgsFeatureId fid, QgsGeometry& geom );
266271
void layerDeleted();
267-
void updatedFields();
272+
void invalidate();
268273

269274
private:
270275

src/core/raster/qgsrasterlayer.h

-5
Original file line numberDiff line numberDiff line change
@@ -375,11 +375,6 @@ class CORE_EXPORT QgsRasterLayer : public QgsMapLayer
375375
/** \brief Signal for notifying listeners of long running processes */
376376
void progressUpdate( int theValue );
377377

378-
/**
379-
* This is emitted whenever data or metadata (e.g. color table, extent) has changed
380-
*/
381-
void dataChanged();
382-
383378
protected:
384379
/** \brief Read the symbology for the current layer from the Dom node supplied */
385380
bool readSymbology( const QDomNode& node, QString& errorMessage ) override;

src/gui/attributetable/qgsattributetablemodel.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,8 @@ void QgsAttributeTableModel::loadLayer()
369369

370370
emit finished();
371371

372+
connect( mLayerCache, SIGNAL( invalidated() ), this, SLOT( loadLayer() ) );
373+
372374
mFieldCount = mAttributes.size();
373375
}
374376

src/gui/attributetable/qgsattributetablemodel.h

+7-6
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,6 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
6262
*/
6363
QgsAttributeTableModel( QgsVectorLayerCache *layerCache, QObject *parent = 0 );
6464

65-
/**
66-
* Loads the layer into the model
67-
* Preferably to be called, before basing any other models on this model
68-
*/
69-
virtual void loadLayer();
70-
7165
/**
7266
* Returns the number of rows
7367
* @param parent parent index
@@ -224,6 +218,13 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
224218
*/
225219
const QgsAttributeEditorContext& editorContext() const { return mEditorContext; }
226220

221+
public slots:
222+
/**
223+
* Loads the layer into the model
224+
* Preferably to be called, before using this model as source for any other proxy model
225+
*/
226+
virtual void loadLayer();
227+
227228
signals:
228229
/**
229230
* Model has been changed

src/providers/ogr/qgsogrprovider.cpp

+54-51
Original file line numberDiff line numberDiff line change
@@ -132,52 +132,53 @@ void QgsOgrProvider::repack()
132132
QByteArray layerName = OGR_FD_GetName( OGR_L_GetLayerDefn( ogrOrigLayer ) );
133133

134134
// run REPACK on shape files
135-
if ( mDataModified )
136-
{
137-
QByteArray sql = QByteArray( "REPACK " ) + layerName; // don't quote the layer name as it works with spaces in the name and won't work if the name is quoted
138-
QgsDebugMsg( QString( "SQL: %1" ).arg( FROM8( sql ) ) );
139-
OGR_DS_ExecuteSQL( ogrDataSource, sql.constData(), NULL, NULL );
135+
QByteArray sql = QByteArray( "REPACK " ) + layerName; // don't quote the layer name as it works with spaces in the name and won't work if the name is quoted
136+
QgsDebugMsg( QString( "SQL: %1" ).arg( FROM8( sql ) ) );
137+
OGR_DS_ExecuteSQL( ogrDataSource, sql.constData(), NULL, NULL );
140138

141-
if ( mFilePath.endsWith( ".shp", Qt::CaseInsensitive ) || mFilePath.endsWith( ".dbf", Qt::CaseInsensitive ) )
139+
if ( mFilePath.endsWith( ".shp", Qt::CaseInsensitive ) || mFilePath.endsWith( ".dbf", Qt::CaseInsensitive ) )
140+
{
141+
QString packedDbf( mFilePath.left( mFilePath.size() - 4 ) + "_packed.dbf" );
142+
if ( QFile::exists( packedDbf ) )
142143
{
143-
QString packedDbf( mFilePath.left( mFilePath.size() - 4 ) + "_packed.dbf" );
144-
if ( QFile::exists( packedDbf ) )
145-
{
146-
QgsMessageLog::logMessage( tr( "Possible corruption after REPACK detected. %1 still exists. This may point to a permission or locking problem of the original DBF." ).arg( packedDbf ), tr( "OGR" ), QgsMessageLog::CRITICAL );
144+
QgsMessageLog::logMessage( tr( "Possible corruption after REPACK detected. %1 still exists. This may point to a permission or locking problem of the original DBF." ).arg( packedDbf ), tr( "OGR" ), QgsMessageLog::CRITICAL );
147145

148-
OGR_DS_Destroy( ogrDataSource );
149-
ogrLayer = ogrOrigLayer = 0;
146+
OGR_DS_Destroy( ogrDataSource );
147+
ogrLayer = ogrOrigLayer = 0;
150148

151-
ogrDataSource = OGROpen( TO8F( mFilePath ), true, NULL );
152-
if ( ogrDataSource )
149+
ogrDataSource = OGROpen( TO8F( mFilePath ), true, NULL );
150+
if ( ogrDataSource )
151+
{
152+
if ( mLayerName.isNull() )
153153
{
154-
if ( mLayerName.isNull() )
155-
{
156-
ogrOrigLayer = OGR_DS_GetLayer( ogrDataSource, mLayerIndex );
157-
}
158-
else
159-
{
160-
ogrOrigLayer = OGR_DS_GetLayerByName( ogrDataSource, TO8( mLayerName ) );
161-
}
162-
163-
if ( !ogrOrigLayer )
164-
{
165-
QgsMessageLog::logMessage( tr( "Original layer could not be reopened." ), tr( "OGR" ), QgsMessageLog::CRITICAL );
166-
valid = false;
167-
}
168-
169-
ogrLayer = ogrOrigLayer;
154+
ogrOrigLayer = OGR_DS_GetLayer( ogrDataSource, mLayerIndex );
170155
}
171156
else
172157
{
173-
QgsMessageLog::logMessage( tr( "Original datasource could not be reopened." ), tr( "OGR" ), QgsMessageLog::CRITICAL );
174-
valid = false;
158+
ogrOrigLayer = OGR_DS_GetLayerByName( ogrDataSource, TO8( mLayerName ) );
175159
}
160+
161+
if ( !ogrOrigLayer )
162+
{
163+
QgsMessageLog::logMessage( tr( "Original layer could not be reopened." ), tr( "OGR" ), QgsMessageLog::CRITICAL );
164+
mValid = false;
165+
}
166+
167+
ogrLayer = ogrOrigLayer;
168+
}
169+
else
170+
{
171+
QgsMessageLog::logMessage( tr( "Original datasource could not be reopened." ), tr( "OGR" ), QgsMessageLog::CRITICAL );
172+
mValid = false;
176173
}
177174
}
178175

179-
mDataModified = false;
180176
}
177+
178+
long oldcount = mFeaturesCounted;
179+
recalculateFeatureCount();
180+
if ( oldcount != mFeaturesCounted )
181+
emit dataChanged();
181182
}
182183

183184

@@ -265,14 +266,12 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
265266
, mIsSubLayer( false )
266267
, mOgrGeometryTypeFilter( wkbUnknown )
267268
, ogrDriver( 0 )
268-
, valid( false )
269+
, mValid( false )
269270
, geomType( wkbUnknown )
270-
, featuresCounted( -1 )
271-
, mDataModified( false )
271+
, mFeaturesCounted( -1 )
272272
, mWriteAccess( false )
273+
, mShapefileMayBeCorrupted( false )
273274
{
274-
QgsCPLErrorHandler handler;
275-
276275
QgsApplication::registerOgrDrivers();
277276

278277
QSettings settings;
@@ -414,8 +413,8 @@ QgsOgrProvider::QgsOgrProvider( QString const & uri )
414413
// check that the initial encoding setting is fit for this layer
415414
setEncoding( encoding() );
416415

417-
valid = setSubsetString( mSubsetString );
418-
if ( valid )
416+
mValid = setSubsetString( mSubsetString );
417+
if ( mValid )
419418
{
420419
QgsDebugMsg( "Data source is valid" );
421420
}
@@ -480,7 +479,7 @@ bool QgsOgrProvider::setSubsetString( QString theSQL, bool updateFeatureCount )
480479
{
481480
QgsCPLErrorHandler handler;
482481

483-
if ( theSQL == mSubsetString && featuresCounted >= 0 )
482+
if ( theSQL == mSubsetString && mFeaturesCounted >= 0 )
484483
return true;
485484

486485
OGRLayerH prevLayer = ogrLayer;
@@ -609,7 +608,7 @@ OGRwkbGeometryType QgsOgrProvider::ogrWkbGeometryTypeFromName( QString typeName
609608
QStringList QgsOgrProvider::subLayers() const
610609
{
611610
QgsDebugMsg( "Entered." );
612-
if ( !valid )
611+
if ( !mValid )
613612
{
614613
return QStringList();
615614
}
@@ -954,7 +953,7 @@ QGis::WkbType QgsOgrProvider::geometryType() const
954953
*/
955954
long QgsOgrProvider::featureCount() const
956955
{
957-
return featuresCounted;
956+
return mFeaturesCounted;
958957
}
959958

960959

@@ -969,7 +968,7 @@ const QgsFields & QgsOgrProvider::fields() const
969968
// actually has features
970969
bool QgsOgrProvider::isValid()
971970
{
972-
return valid;
971+
return mValid;
973972
}
974973

975974
bool QgsOgrProvider::addFeature( QgsFeature& f )
@@ -1347,6 +1346,7 @@ bool QgsOgrProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
13471346
theNewGeometry = 0;
13481347
continue;
13491348
}
1349+
mShapefileMayBeCorrupted = true;
13501350

13511351
OGR_F_Destroy( theOGRFeature );
13521352
}
@@ -1389,8 +1389,6 @@ bool QgsOgrProvider::createAttributeIndex( int field )
13891389

13901390
bool QgsOgrProvider::deleteFeatures( const QgsFeatureIds & id )
13911391
{
1392-
QgsCPLErrorHandler handler;
1393-
13941392
bool returnvalue = true;
13951393
for ( QgsFeatureIds::const_iterator it = id.begin(); it != id.end(); ++it )
13961394
{
@@ -1432,6 +1430,8 @@ bool QgsOgrProvider::deleteFeature( QgsFeatureId id )
14321430
return false;
14331431
}
14341432

1433+
mShapefileMayBeCorrupted = true;
1434+
14351435
return true;
14361436
}
14371437

@@ -2457,6 +2457,11 @@ bool QgsOgrProvider::syncToDisc()
24572457
pushError( tr( "OGR error syncing to disk: %1" ).arg( CPLGetLastErrorMsg() ) );
24582458
}
24592459

2460+
if ( mShapefileMayBeCorrupted )
2461+
repack();
2462+
2463+
mShapefileMayBeCorrupted = false;
2464+
24602465
//for shapefiles: is there already a spatial index?
24612466
if ( !mFilePath.isEmpty() )
24622467
{
@@ -2478,8 +2483,6 @@ bool QgsOgrProvider::syncToDisc()
24782483
}
24792484
}
24802485

2481-
mDataModified = true;
2482-
24832486
return true;
24842487
}
24852488

@@ -2496,11 +2499,11 @@ void QgsOgrProvider::recalculateFeatureCount()
24962499
// so we remove it if there's any and then put it back
24972500
if ( mOgrGeometryTypeFilter == wkbUnknown )
24982501
{
2499-
featuresCounted = OGR_L_GetFeatureCount( ogrLayer, true );
2502+
mFeaturesCounted = OGR_L_GetFeatureCount( ogrLayer, true );
25002503
}
25012504
else
25022505
{
2503-
featuresCounted = 0;
2506+
mFeaturesCounted = 0;
25042507
OGR_L_ResetReading( ogrLayer );
25052508
setRelevantFields( ogrLayer, true, QgsAttributeList() );
25062509
OGR_L_ResetReading( ogrLayer );
@@ -2511,7 +2514,7 @@ void QgsOgrProvider::recalculateFeatureCount()
25112514
if ( geom )
25122515
{
25132516
OGRwkbGeometryType gType = OGR_G_GetGeometryType( geom );
2514-
if ( gType == mOgrGeometryTypeFilter ) featuresCounted++;
2517+
if ( gType == mOgrGeometryTypeFilter ) mFeaturesCounted++;
25152518
}
25162519
OGR_F_Destroy( fet );
25172520
}

src/providers/ogr/qgsogrprovider.h

+4-5
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,10 @@ class QgsOgrProvider : public QgsVectorDataProvider
322322
// Friendly name of the OGR Driver that was actually used to open the layer
323323
QString ogrDriverName;
324324

325-
bool valid;
325+
bool mValid;
326326

327327
OGRwkbGeometryType geomType;
328-
long featuresCounted;
329-
330-
//! Data has been modified - REPACK before creating a spatialindex
331-
bool mDataModified;
328+
long mFeaturesCounted;
332329

333330
mutable QStringList mSubLayerList;
334331

@@ -346,6 +343,8 @@ class QgsOgrProvider : public QgsVectorDataProvider
346343

347344
/** whether the file is opened in write mode*/
348345
bool mWriteAccess;
346+
347+
bool mShapefileMayBeCorrupted;
349348
};
350349

351350

0 commit comments

Comments
 (0)