Skip to content

Commit

Permalink
[bugfix] offline editing converting offline twice
Browse files Browse the repository at this point in the history
Fixes #10537: Converting offline twice within the same
instance causing unusable offline state.

The problem was due to spatialite connection not being
invalidated.  When the new offline layer is re-created
the provider connection doesn't pick the latest commits.

Funded by Boundless
  • Loading branch information
elpaso authored and dakcarto committed Apr 22, 2016
1 parent 3a89da0 commit f045492
Showing 1 changed file with 40 additions and 29 deletions.
69 changes: 40 additions & 29 deletions src/core/qgsofflineediting.cpp
Expand Up @@ -65,6 +65,17 @@ QgsOfflineEditing::~QgsOfflineEditing()
/**
* convert current project to offline project
* returns offline project file path
*
* Workflow:
* - copy layers to spatialite
* - create spatialite db at offlineDataPath
* - create table for each layer
* - add new spatialite layer
* - copy features
* - save as offline project
* - mark offline layers
* - remove remote layers
* - mark as offline project
*/
bool QgsOfflineEditing::convertToOfflineProject( const QString& offlineDataPath, const QString& offlineDbFile, const QStringList& layerIds )
{
Expand Down Expand Up @@ -177,17 +188,6 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString& offlineDataPath,
}

return false;

// Workflow:
// copy layers to spatialite
// create spatialite db at offlineDataPath
// create table for each layer
// add new spatialite layer
// copy features
// save as offline project
// mark offline layers
// remove remote layers
// mark as offline project
}

bool QgsOfflineEditing::isOfflineProject()
Expand Down Expand Up @@ -288,11 +288,14 @@ void QgsOfflineEditing::synchronize()
showWarning( remoteLayer->commitErrors().join( "\n" ) );
}
}

// Invalidate the connection to force a reload if the project is put offline
// again with the same path
offlineLayer->dataProvider()->invalidateConnections( QgsDataSourceURI( offlineLayer->source() ).database() );
// remove offline layer
QgsMapLayerRegistry::instance()->removeMapLayers(
( QStringList() << qgisLayerId ) );


// disable offline project
QString projectTitle = QgsProject::instance()->title();
projectTitle.remove( QRegExp( " \\(offline\\)$" ) );
Expand Down Expand Up @@ -460,6 +463,7 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
return nullptr;

QString tableName = layer->id();
QgsDebugMsg( QString( "Creating offline table %1 ..." ).arg( tableName ) );

// create table
QString sql = QString( "CREATE TABLE '%1' (" ).arg( tableName );
Expand Down Expand Up @@ -541,9 +545,10 @@ QgsVectorLayer* QgsOfflineEditing::copyVectorLayer( QgsVectorLayer* layer, sqlit
if ( rc == SQLITE_OK )
{
// add new layer
QgsVectorLayer* newLayer = new QgsVectorLayer( QString( "dbname='%1' table='%2'%3 sql=" )
.arg( offlineDbPath,
tableName, layer->hasGeometryType() ? "(Geometry)" : "" ),
QString connectionString = QString( "dbname='%1' table='%2'%3 sql=" )
.arg( offlineDbPath,
tableName, layer->hasGeometryType() ? "(Geometry)" : "" );
QgsVectorLayer* newLayer = new QgsVectorLayer( connectionString,
layer->name() + " (offline)", "spatialite" );
if ( newLayer->isValid() )
{
Expand Down Expand Up @@ -1296,33 +1301,39 @@ void QgsOfflineEditing::committedGeometriesChanges( const QString& qgisLayerId,
void QgsOfflineEditing::startListenFeatureChanges()
{
QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer *>( sender() );
// enable logging
connect( vLayer->editBuffer(), SIGNAL( committedAttributesAdded( const QString&, const QList<QgsField>& ) ),
this, SLOT( committedAttributesAdded( const QString&, const QList<QgsField>& ) ) );
// enable logging, check if editBuffer is not null
if ( vLayer->editBuffer() )
{
connect( vLayer->editBuffer(), SIGNAL( committedAttributesAdded( const QString&, const QList<QgsField>& ) ),
this, SLOT( committedAttributesAdded( const QString&, const QList<QgsField>& ) ) );
connect( vLayer->editBuffer(), SIGNAL( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ),
this, SLOT( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ) );
connect( vLayer->editBuffer(), SIGNAL( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ),
this, SLOT( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ) );
}
connect( vLayer, SIGNAL( committedFeaturesAdded( const QString&, const QgsFeatureList& ) ),
this, SLOT( committedFeaturesAdded( const QString&, const QgsFeatureList& ) ) );
connect( vLayer, SIGNAL( committedFeaturesRemoved( const QString&, const QgsFeatureIds& ) ),
this, SLOT( committedFeaturesRemoved( const QString&, const QgsFeatureIds& ) ) );
connect( vLayer->editBuffer(), SIGNAL( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ),
this, SLOT( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ) );
connect( vLayer->editBuffer(), SIGNAL( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ),
this, SLOT( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ) );
}

void QgsOfflineEditing::stopListenFeatureChanges()
{
QgsVectorLayer* vLayer = qobject_cast<QgsVectorLayer *>( sender() );
// disable logging
disconnect( vLayer->editBuffer(), SIGNAL( committedAttributesAdded( const QString&, const QList<QgsField>& ) ),
this, SLOT( committedAttributesAdded( const QString&, const QList<QgsField>& ) ) );
// disable logging, check if editBuffer is not null
if ( vLayer->editBuffer() )
{
disconnect( vLayer->editBuffer(), SIGNAL( committedAttributesAdded( const QString&, const QList<QgsField>& ) ),
this, SLOT( committedAttributesAdded( const QString&, const QList<QgsField>& ) ) );
disconnect( vLayer->editBuffer(), SIGNAL( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ),
this, SLOT( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ) );
disconnect( vLayer->editBuffer(), SIGNAL( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ),
this, SLOT( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ) );
}
disconnect( vLayer, SIGNAL( committedFeaturesAdded( const QString&, const QgsFeatureList& ) ),
this, SLOT( committedFeaturesAdded( const QString&, const QgsFeatureList& ) ) );
disconnect( vLayer, SIGNAL( committedFeaturesRemoved( const QString&, const QgsFeatureIds& ) ),
this, SLOT( committedFeaturesRemoved( const QString&, const QgsFeatureIds& ) ) );
disconnect( vLayer->editBuffer(), SIGNAL( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ),
this, SLOT( committedAttributeValuesChanges( const QString&, const QgsChangedAttributesMap& ) ) );
disconnect( vLayer->editBuffer(), SIGNAL( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ),
this, SLOT( committedGeometriesChanges( const QString&, const QgsGeometryMap& ) ) );
}

void QgsOfflineEditing::layerAdded( QgsMapLayer* layer )
Expand Down

4 comments on commit f045492

@nyalldawson
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elpaso @dakcarto Great to see offline conversion getting some love - these issues have been tagged as blockers for ages 👍

@gioman
Copy link
Contributor

@gioman gioman commented on f045492 Apr 22, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@elpaso @dakcarto many thanks for the fix! it makes this core tool usable again.

@dakcarto
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. @elpaso did all the work.

@dakcarto
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, backporting to release-2_14 now.

Please sign in to comment.