Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 3d0787c

Browse files
suricactusgithub-actions[bot]
authored andcommittedJun 11, 2021
Add layer validity checks and hints where not to expect nullptr
1 parent 6938593 commit 3d0787c

File tree

1 file changed

+137
-77
lines changed

1 file changed

+137
-77
lines changed
 

‎src/core/qgsofflineediting.cpp

Lines changed: 137 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,11 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath,
116116
{
117117
QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerId );
118118
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
119-
if ( !vl )
119+
if ( !vl || !vl->isValid() )
120+
{
121+
QgsDebugMsgLevel( QStringLiteral( "Layer %1 is invalid" ).arg( layerId ), 4 );
120122
continue;
123+
}
121124
QgsVectorJoinList joins = vl->vectorJoins();
122125

123126
// Layer names will be appended an _offline suffix
@@ -131,7 +134,7 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath,
131134
{
132135
QgsVectorLayer *vl = joinIt->joinLayer();
133136

134-
if ( vl )
137+
if ( vl && vl->isValid() )
135138
joinIt->setPrefix( vl->name() + '_' );
136139
}
137140
++joinIt;
@@ -148,11 +151,11 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath,
148151

149152
QgsMapLayer *layer = QgsProject::instance()->mapLayer( layerIds.at( i ) );
150153
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( layer );
151-
if ( vl )
154+
if ( vl && vl->isValid() )
152155
{
153156
QString origLayerId = vl->id();
154157
QgsVectorLayer *newLayer = copyVectorLayer( vl, database.get(), dbPath, onlySelected, containerType, layerNameSuffix );
155-
if ( newLayer )
158+
if ( newLayer && newLayer->isValid() )
156159
{
157160
layerIdMapping.insert( origLayerId, newLayer );
158161
//append individual layer setting on snapping settings
@@ -174,13 +177,13 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath,
174177
{
175178
QgsVectorLayer *newLayer = layerIdMapping.value( it.key() );
176179

177-
if ( newLayer )
180+
if ( newLayer && newLayer->isValid() )
178181
{
179182
const QList<QgsVectorLayerJoinInfo> joins = it.value();
180183
for ( QgsVectorLayerJoinInfo join : joins )
181184
{
182185
QgsVectorLayer *newJoinedLayer = layerIdMapping.value( join.joinLayerId() );
183-
if ( newJoinedLayer )
186+
if ( newJoinedLayer && newJoinedLayer->isValid() )
184187
{
185188
// If the layer has been offline'd, update join information
186189
join.setJoinLayer( newJoinedLayer );
@@ -234,8 +237,15 @@ void QgsOfflineEditing::synchronize()
234237
for ( QMap<QString, QgsMapLayer *>::iterator layer_it = mapLayers.begin() ; layer_it != mapLayers.end(); ++layer_it )
235238
{
236239
QgsMapLayer *layer = layer_it.value();
240+
237241
if ( layer->customProperty( CUSTOM_PROPERTY_IS_OFFLINE_EDITABLE, false ).toBool() )
238242
{
243+
if ( !layer->isValid() )
244+
{
245+
QgsDebugMsgLevel( QStringLiteral( "Skipping offline layer %1 because it is an invalid layer" ).arg( layer->id() ), 4 );
246+
continue;
247+
}
248+
239249
offlineLayers << layer;
240250
}
241251
}
@@ -270,90 +280,97 @@ void QgsOfflineEditing::synchronize()
270280

271281
QgsVectorLayer *offlineLayer = qobject_cast<QgsVectorLayer *>( layer );
272282

273-
// register this layer with the central layers registry
274-
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << remoteLayer, true );
275-
276-
// copy style
277-
copySymbology( offlineLayer, remoteLayer );
278-
updateRelations( offlineLayer, remoteLayer );
279-
updateMapThemes( offlineLayer, remoteLayer );
280-
updateLayerOrder( offlineLayer, remoteLayer );
281-
282-
//append individual layer setting on snapping settings
283-
snappingConfig.setIndividualLayerSettings( remoteLayer, snappingConfig.individualLayerSettings( offlineLayer ) );
284-
snappingConfig.removeLayers( QList<QgsMapLayer *>() << offlineLayer );
285-
286-
//set QgsLayerTreeNode properties back
287-
QgsLayerTreeLayer *layerTreeLayer = QgsProject::instance()->layerTreeRoot()->findLayer( offlineLayer->id() );
288-
QgsLayerTreeLayer *newLayerTreeLayer = QgsProject::instance()->layerTreeRoot()->findLayer( remoteLayer->id() );
289-
newLayerTreeLayer->setCustomProperty( CUSTOM_SHOW_FEATURE_COUNT, layerTreeLayer->customProperty( CUSTOM_SHOW_FEATURE_COUNT ) );
290-
291-
// apply layer edit log
292-
QString qgisLayerId = layer->id();
293-
QString sql = QStringLiteral( "SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
294-
int layerId = sqlQueryInt( database.get(), sql, -1 );
295-
if ( layerId != -1 )
283+
if ( offlineLayer->isValid() )
296284
{
297-
remoteLayer->startEditing();
298-
299-
// TODO: only get commitNos of this layer?
300-
int commitNo = getCommitNo( database.get() );
301-
QgsDebugMsgLevel( QStringLiteral( "Found %1 commits" ).arg( commitNo ), 4 );
302-
for ( int i = 0; i < commitNo; i++ )
285+
// register this layer with the central layers registry
286+
QgsProject::instance()->addMapLayers( QList<QgsMapLayer *>() << remoteLayer, true );
287+
288+
// copy style
289+
copySymbology( offlineLayer, remoteLayer );
290+
updateRelations( offlineLayer, remoteLayer );
291+
updateMapThemes( offlineLayer, remoteLayer );
292+
updateLayerOrder( offlineLayer, remoteLayer );
293+
294+
//append individual layer setting on snapping settings
295+
snappingConfig.setIndividualLayerSettings( remoteLayer, snappingConfig.individualLayerSettings( offlineLayer ) );
296+
snappingConfig.removeLayers( QList<QgsMapLayer *>() << offlineLayer );
297+
298+
//set QgsLayerTreeNode properties back
299+
QgsLayerTreeLayer *layerTreeLayer = QgsProject::instance()->layerTreeRoot()->findLayer( offlineLayer->id() );
300+
QgsLayerTreeLayer *newLayerTreeLayer = QgsProject::instance()->layerTreeRoot()->findLayer( remoteLayer->id() );
301+
newLayerTreeLayer->setCustomProperty( CUSTOM_SHOW_FEATURE_COUNT, layerTreeLayer->customProperty( CUSTOM_SHOW_FEATURE_COUNT ) );
302+
303+
// apply layer edit log
304+
QString qgisLayerId = layer->id();
305+
QString sql = QStringLiteral( "SELECT \"id\" FROM 'log_layer_ids' WHERE \"qgis_id\" = '%1'" ).arg( qgisLayerId );
306+
int layerId = sqlQueryInt( database.get(), sql, -1 );
307+
if ( layerId != -1 )
303308
{
304-
QgsDebugMsgLevel( QStringLiteral( "Apply commits chronologically" ), 4 );
305-
// apply commits chronologically
306-
applyAttributesAdded( remoteLayer, database.get(), layerId, i );
307-
applyAttributeValueChanges( offlineLayer, remoteLayer, database.get(), layerId, i );
308-
applyGeometryChanges( remoteLayer, database.get(), layerId, i );
309-
}
309+
remoteLayer->startEditing();
310+
311+
// TODO: only get commitNos of this layer?
312+
int commitNo = getCommitNo( database.get() );
313+
QgsDebugMsgLevel( QStringLiteral( "Found %1 commits" ).arg( commitNo ), 4 );
314+
for ( int i = 0; i < commitNo; i++ )
315+
{
316+
QgsDebugMsgLevel( QStringLiteral( "Apply commits chronologically" ), 4 );
317+
// apply commits chronologically
318+
applyAttributesAdded( remoteLayer, database.get(), layerId, i );
319+
applyAttributeValueChanges( offlineLayer, remoteLayer, database.get(), layerId, i );
320+
applyGeometryChanges( remoteLayer, database.get(), layerId, i );
321+
}
310322

311-
applyFeaturesAdded( offlineLayer, remoteLayer, database.get(), layerId );
312-
applyFeaturesRemoved( remoteLayer, database.get(), layerId );
323+
applyFeaturesAdded( offlineLayer, remoteLayer, database.get(), layerId );
324+
applyFeaturesRemoved( remoteLayer, database.get(), layerId );
313325

314-
if ( remoteLayer->commitChanges() )
315-
{
316-
// update fid lookup
317-
updateFidLookup( remoteLayer, database.get(), layerId );
318-
319-
// clear edit log for this layer
320-
sql = QStringLiteral( "DELETE FROM 'log_added_attrs' WHERE \"layer_id\" = %1" ).arg( layerId );
321-
sqlExec( database.get(), sql );
322-
sql = QStringLiteral( "DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
323-
sqlExec( database.get(), sql );
324-
sql = QStringLiteral( "DELETE FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
325-
sqlExec( database.get(), sql );
326-
sql = QStringLiteral( "DELETE FROM 'log_feature_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
327-
sqlExec( database.get(), sql );
328-
sql = QStringLiteral( "DELETE FROM 'log_geometry_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
329-
sqlExec( database.get(), sql );
326+
if ( remoteLayer->commitChanges() )
327+
{
328+
// update fid lookup
329+
updateFidLookup( remoteLayer, database.get(), layerId );
330+
331+
// clear edit log for this layer
332+
sql = QStringLiteral( "DELETE FROM 'log_added_attrs' WHERE \"layer_id\" = %1" ).arg( layerId );
333+
sqlExec( database.get(), sql );
334+
sql = QStringLiteral( "DELETE FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
335+
sqlExec( database.get(), sql );
336+
sql = QStringLiteral( "DELETE FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
337+
sqlExec( database.get(), sql );
338+
sql = QStringLiteral( "DELETE FROM 'log_feature_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
339+
sqlExec( database.get(), sql );
340+
sql = QStringLiteral( "DELETE FROM 'log_geometry_updates' WHERE \"layer_id\" = %1" ).arg( layerId );
341+
sqlExec( database.get(), sql );
342+
}
343+
else
344+
{
345+
showWarning( remoteLayer->commitErrors().join( QLatin1Char( '\n' ) ) );
346+
}
330347
}
331348
else
332349
{
333-
showWarning( remoteLayer->commitErrors().join( QLatin1Char( '\n' ) ) );
350+
QgsDebugMsg( QStringLiteral( "Could not find the layer id in the edit logs!" ) );
334351
}
352+
// Invalidate the connection to force a reload if the project is put offline
353+
// again with the same path
354+
offlineLayer->dataProvider()->invalidateConnections( QgsDataSourceUri( offlineLayer->source() ).database() );
355+
// remove offline layer
356+
QgsProject::instance()->removeMapLayers( QStringList() << qgisLayerId );
357+
358+
359+
// disable offline project
360+
QString projectTitle = QgsProject::instance()->title();
361+
projectTitle.remove( QRegExp( " \\(offline\\)$" ) );
362+
QgsProject::instance()->setTitle( projectTitle );
363+
QgsProject::instance()->removeEntry( PROJECT_ENTRY_SCOPE_OFFLINE, PROJECT_ENTRY_KEY_OFFLINE_DB_PATH );
364+
remoteLayer->reload(); //update with other changes
335365
}
336366
else
337367
{
338-
QgsDebugMsg( QStringLiteral( "Could not find the layer id in the edit logs!" ) );
368+
QgsDebugMsg( QStringLiteral( "Offline layer %1 is not valid!" ).arg( offlineLayer->id() ) );
339369
}
340-
// Invalidate the connection to force a reload if the project is put offline
341-
// again with the same path
342-
offlineLayer->dataProvider()->invalidateConnections( QgsDataSourceUri( offlineLayer->source() ).database() );
343-
// remove offline layer
344-
QgsProject::instance()->removeMapLayers( QStringList() << qgisLayerId );
345-
346-
347-
// disable offline project
348-
QString projectTitle = QgsProject::instance()->title();
349-
projectTitle.remove( QRegExp( " \\(offline\\)$" ) );
350-
QgsProject::instance()->setTitle( projectTitle );
351-
QgsProject::instance()->removeEntry( PROJECT_ENTRY_SCOPE_OFFLINE, PROJECT_ENTRY_KEY_OFFLINE_DB_PATH );
352-
remoteLayer->reload(); //update with other changes
353370
}
354371
else
355372
{
356-
QgsDebugMsg( QStringLiteral( "Remote layer is not valid!" ) );
373+
QgsDebugMsg( QStringLiteral( "Remote layer %1 is not valid!" ).arg( remoteLayer->id() ) );
357374
}
358375
}
359376

@@ -544,8 +561,11 @@ void QgsOfflineEditing::createLoggingTables( sqlite3 *db )
544561

545562
QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlite3 *db, const QString &offlineDbPath, bool onlySelected, ContainerType containerType, const QString &layerNameSuffix )
546563
{
547-
if ( !layer )
564+
if ( !layer || !layer->isValid() )
565+
{
566+
QgsDebugMsgLevel( QStringLiteral( "Layer %1 is invalid and cannot be coppied" ).arg( layer ? layer->id() : QStringLiteral( "<UNKNOWN>" ) ), 4 );
548567
return nullptr;
568+
}
549569

550570
QString tableName = layer->id();
551571
QgsDebugMsgLevel( QStringLiteral( "Creating offline table %1 ..." ).arg( tableName ), 4 );
@@ -776,7 +796,7 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
776796
}
777797
}
778798

779-
if ( newLayer->isValid() )
799+
if ( newLayer && newLayer->isValid() )
780800
{
781801

782802
// copy features
@@ -930,6 +950,8 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
930950

931951
void QgsOfflineEditing::applyAttributesAdded( QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId, int commitNo )
932952
{
953+
Q_ASSERT( remoteLayer );
954+
933955
QString sql = QStringLiteral( "SELECT \"name\", \"type\", \"length\", \"precision\", \"comment\" FROM 'log_added_attrs' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
934956
QList<QgsField> fields = sqlQueryAttributesAdded( db, sql );
935957

@@ -967,6 +989,9 @@ void QgsOfflineEditing::applyAttributesAdded( QgsVectorLayer *remoteLayer, sqlit
967989

968990
void QgsOfflineEditing::applyFeaturesAdded( QgsVectorLayer *offlineLayer, QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId )
969991
{
992+
Q_ASSERT( offlineLayer );
993+
Q_ASSERT( remoteLayer );
994+
970995
QString sql = QStringLiteral( "SELECT \"fid\" FROM 'log_added_features' WHERE \"layer_id\" = %1" ).arg( layerId );
971996
const QList<int> featureIdInts = sqlQueryInts( db, sql );
972997
QgsFeatureIds newFeatureIds;
@@ -1013,6 +1038,8 @@ void QgsOfflineEditing::applyFeaturesAdded( QgsVectorLayer *offlineLayer, QgsVec
10131038

10141039
void QgsOfflineEditing::applyFeaturesRemoved( QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId )
10151040
{
1041+
Q_ASSERT( remoteLayer );
1042+
10161043
QString sql = QStringLiteral( "SELECT \"fid\" FROM 'log_removed_features' WHERE \"layer_id\" = %1" ).arg( layerId );
10171044
QgsFeatureIds values = sqlQueryFeaturesRemoved( db, sql );
10181045

@@ -1030,6 +1057,9 @@ void QgsOfflineEditing::applyFeaturesRemoved( QgsVectorLayer *remoteLayer, sqlit
10301057

10311058
void QgsOfflineEditing::applyAttributeValueChanges( QgsVectorLayer *offlineLayer, QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId, int commitNo )
10321059
{
1060+
Q_ASSERT( offlineLayer );
1061+
Q_ASSERT( remoteLayer );
1062+
10331063
QString sql = QStringLiteral( "SELECT \"fid\", \"attr\", \"value\" FROM 'log_feature_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2 " ).arg( layerId ).arg( commitNo );
10341064
AttributeValueChanges values = sqlQueryAttributeValueChanges( db, sql );
10351065

@@ -1049,6 +1079,8 @@ void QgsOfflineEditing::applyAttributeValueChanges( QgsVectorLayer *offlineLayer
10491079

10501080
void QgsOfflineEditing::applyGeometryChanges( QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId, int commitNo )
10511081
{
1082+
Q_ASSERT( remoteLayer );
1083+
10521084
QString sql = QStringLiteral( "SELECT \"fid\", \"geom_wkt\" FROM 'log_geometry_updates' WHERE \"layer_id\" = %1 AND \"commit_no\" = %2" ).arg( layerId ).arg( commitNo );
10531085
GeometryChanges values = sqlQueryGeometryChanges( db, sql );
10541086

@@ -1066,6 +1098,8 @@ void QgsOfflineEditing::applyGeometryChanges( QgsVectorLayer *remoteLayer, sqlit
10661098

10671099
void QgsOfflineEditing::updateFidLookup( QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId )
10681100
{
1101+
Q_ASSERT( remoteLayer );
1102+
10691103
// update fid lookup for added features
10701104

10711105
// get remote added fids
@@ -1112,6 +1146,9 @@ void QgsOfflineEditing::updateFidLookup( QgsVectorLayer *remoteLayer, sqlite3 *d
11121146

11131147
void QgsOfflineEditing::copySymbology( QgsVectorLayer *sourceLayer, QgsVectorLayer *targetLayer )
11141148
{
1149+
Q_ASSERT( sourceLayer );
1150+
Q_ASSERT( targetLayer );
1151+
11151152
targetLayer->styleManager()->copyStylesFrom( sourceLayer->styleManager() );
11161153

11171154
QString error;
@@ -1132,6 +1169,9 @@ void QgsOfflineEditing::copySymbology( QgsVectorLayer *sourceLayer, QgsVectorLay
11321169

11331170
void QgsOfflineEditing::updateRelations( QgsVectorLayer *sourceLayer, QgsVectorLayer *targetLayer )
11341171
{
1172+
Q_ASSERT( sourceLayer );
1173+
Q_ASSERT( targetLayer );
1174+
11351175
QgsRelationManager *relationManager = QgsProject::instance()->relationManager();
11361176
const QList<QgsRelation> referencedRelations = relationManager->referencedRelations( sourceLayer );
11371177

@@ -1154,6 +1194,9 @@ void QgsOfflineEditing::updateRelations( QgsVectorLayer *sourceLayer, QgsVectorL
11541194

11551195
void QgsOfflineEditing::updateMapThemes( QgsVectorLayer *sourceLayer, QgsVectorLayer *targetLayer )
11561196
{
1197+
Q_ASSERT( sourceLayer );
1198+
Q_ASSERT( targetLayer );
1199+
11571200
QgsMapThemeCollection *mapThemeCollection = QgsProject::instance()->mapThemeCollection();
11581201
const QStringList mapThemeNames = mapThemeCollection->mapThemes();
11591202

@@ -1179,6 +1222,9 @@ void QgsOfflineEditing::updateMapThemes( QgsVectorLayer *sourceLayer, QgsVectorL
11791222

11801223
void QgsOfflineEditing::updateLayerOrder( QgsVectorLayer *sourceLayer, QgsVectorLayer *targetLayer )
11811224
{
1225+
Q_ASSERT( sourceLayer );
1226+
Q_ASSERT( targetLayer );
1227+
11821228
QList<QgsMapLayer *> layerOrder = QgsProject::instance()->layerTreeRoot()->customLayerOrder();
11831229

11841230
auto iterator = layerOrder.begin();
@@ -1206,6 +1252,9 @@ void QgsOfflineEditing::updateLayerOrder( QgsVectorLayer *sourceLayer, QgsVector
12061252
// NOTE: use this to map column indices in case the remote geometry column is not last
12071253
QMap<int, int> QgsOfflineEditing::attributeLookup( QgsVectorLayer *offlineLayer, QgsVectorLayer *remoteLayer )
12081254
{
1255+
Q_ASSERT( offlineLayer );
1256+
Q_ASSERT( remoteLayer );
1257+
12091258
const QgsAttributeList &offlineAttrs = offlineLayer->attributeList();
12101259

12111260
QMap < int /*offline attr*/, int /*remote attr*/ > attrLookup;
@@ -1632,6 +1681,9 @@ void QgsOfflineEditing::committedGeometriesChanges( const QString &qgisLayerId,
16321681
void QgsOfflineEditing::startListenFeatureChanges()
16331682
{
16341683
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( sender() );
1684+
1685+
Q_ASSERT( vLayer );
1686+
16351687
// enable logging, check if editBuffer is not null
16361688
if ( vLayer->editBuffer() )
16371689
{
@@ -1652,6 +1704,9 @@ void QgsOfflineEditing::startListenFeatureChanges()
16521704
void QgsOfflineEditing::stopListenFeatureChanges()
16531705
{
16541706
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( sender() );
1707+
1708+
Q_ASSERT( vLayer );
1709+
16551710
// disable logging, check if editBuffer is not null
16561711
if ( vLayer->editBuffer() )
16571712
{
@@ -1671,10 +1726,15 @@ void QgsOfflineEditing::stopListenFeatureChanges()
16711726

16721727
void QgsOfflineEditing::layerAdded( QgsMapLayer *layer )
16731728
{
1729+
Q_ASSERT( layer );
1730+
16741731
// detect offline layer
16751732
if ( layer->customProperty( CUSTOM_PROPERTY_IS_OFFLINE_EDITABLE, false ).toBool() )
16761733
{
16771734
QgsVectorLayer *vLayer = qobject_cast<QgsVectorLayer *>( layer );
1735+
1736+
Q_ASSERT( vLayer );
1737+
16781738
connect( vLayer, &QgsVectorLayer::editingStarted, this, &QgsOfflineEditing::startListenFeatureChanges );
16791739
connect( vLayer, &QgsVectorLayer::editingStopped, this, &QgsOfflineEditing::stopListenFeatureChanges );
16801740
}

0 commit comments

Comments
 (0)
Please sign in to comment.