Skip to content
Permalink
Browse files

suffix parameter in convertToOfflineProject to be able to control the…

… suffix in layernames of the offline layer.

cherry-picks of commits:
23e661a65f0adfead89fb7ce702f874907999d1c
7428b68e8ea583dfb2ad4bcb49ee40879cb87a06
3d02b3dfcd9fa507248bb909ae129a1c218fa329
eb66677b597f7b33efd60ed15fee75bb9f2c26fa
bcc0c93ae9639a76bcea4cd2b2de282236e31321
b321454dccea3066b007d5687d0c4d9ec8772e91

layer name suffix passed to convertToOfflineProject with ' (offline)' as default
it's written into custom property so in synchronize it can get it from the offline project

tests with suffix on offline layer names

pass empty layer name suffix to offline editing core, to avoid that offline layers are renamed

pass QString() instead of  to have an empty layer name suffix

set IDENTIFIER option in geopackage like we used to because it's out of scope for now

only remove suffix when it's on the end
  • Loading branch information
signedav authored and nyalldawson committed Oct 26, 2020
1 parent 33475aa commit 6e1b23afc7de2b549157dba61ab7bcb205d09bc8
@@ -36,7 +36,7 @@ class QgsOfflineEditing : QObject

QgsOfflineEditing();

bool convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected = false, ContainerType containerType = SpatiaLite );
bool convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected = false, ContainerType containerType = SpatiaLite, const QString &layerNameSuffix = QStringLiteral( " (offline)" ) );
%Docstring
Convert current project for offline editing

@@ -45,6 +45,7 @@ Convert current project for offline editing
:param layerIds: List of layer names to convert
:param onlySelected: Only copy selected features from layers where a selection is present
:param containerType: defines the SQLite file container type like SpatiaLite or GPKG
:param layerNameSuffix: Suffix string added to the offline layer name
%End

bool isOfflineProject() const;
@@ -61,6 +61,7 @@ extern "C"
#define CUSTOM_PROPERTY_REMOTE_PROVIDER "remoteProvider"
#define CUSTOM_SHOW_FEATURE_COUNT "showFeatureCount"
#define CUSTOM_PROPERTY_ORIGINAL_LAYERID "remoteLayerId"
#define CUSTOM_PROPERTY_LAYERNAME_SUFFIX "layerNameSuffix"
#define PROJECT_ENTRY_SCOPE_OFFLINE "OfflineEditingPlugin"
#define PROJECT_ENTRY_KEY_OFFLINE_DB_PATH "/OfflineDbPath"

@@ -85,7 +86,7 @@ QgsOfflineEditing::QgsOfflineEditing()
* - remove remote layers
* - mark as offline project
*/
bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected, ContainerType containerType )
bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected, ContainerType containerType, const QString &layerNameSuffix )
{
if ( layerIds.isEmpty() )
{
@@ -150,7 +151,7 @@ bool QgsOfflineEditing::convertToOfflineProject( const QString &offlineDataPath,
if ( vl )
{
QString origLayerId = vl->id();
QgsVectorLayer *newLayer = copyVectorLayer( vl, database.get(), dbPath, onlySelected, containerType );
QgsVectorLayer *newLayer = copyVectorLayer( vl, database.get(), dbPath, onlySelected, containerType, layerNameSuffix );
if ( newLayer )
{
layerIdMapping.insert( origLayerId, newLayer );
@@ -249,7 +250,9 @@ void QgsOfflineEditing::synchronize()
QString remoteSource = layer->customProperty( CUSTOM_PROPERTY_REMOTE_SOURCE, "" ).toString();
QString remoteProvider = layer->customProperty( CUSTOM_PROPERTY_REMOTE_PROVIDER, "" ).toString();
QString remoteName = layer->name();
remoteName.remove( QRegExp( " \\(offline\\)$" ) );
QString remoteNameSuffix = layer->customProperty( CUSTOM_PROPERTY_LAYERNAME_SUFFIX, " (offline)" ).toString();
if ( remoteName.endsWith( remoteNameSuffix ) )
remoteName.chop( remoteNameSuffix.size() );
const QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
QgsVectorLayer *remoteLayer = new QgsVectorLayer( remoteSource, remoteName, remoteProvider, options );
if ( remoteLayer->isValid() )
@@ -539,7 +542,7 @@ void QgsOfflineEditing::createLoggingTables( sqlite3 *db )
*/
}

QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlite3 *db, const QString &offlineDbPath, bool onlySelected, ContainerType containerType )
QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlite3 *db, const QString &offlineDbPath, bool onlySelected, ContainerType containerType, const QString &layerNameSuffix )
{
if ( !layer )
return nullptr;
@@ -664,7 +667,7 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
tableName, layer->isSpatial() ? "(Geometry)" : "" );
QgsVectorLayer::LayerOptions options { QgsProject::instance()->transformContext() };
newLayer = new QgsVectorLayer( connectionString,
layer->name() + " (offline)", QStringLiteral( "spatialite" ), options );
layer->name() + layerNameSuffix, QStringLiteral( "spatialite" ), options );
break;
}
case GPKG:
@@ -768,7 +771,7 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit

QString uri = QStringLiteral( "%1|layername=%2" ).arg( offlineDbPath, tableName );
QgsVectorLayer::LayerOptions layerOptions { QgsProject::instance()->transformContext() };
newLayer = new QgsVectorLayer( uri, layer->name() + " (offline)", QStringLiteral( "ogr" ), layerOptions );
newLayer = new QgsVectorLayer( uri, layer->name() + layerNameSuffix, QStringLiteral( "ogr" ), layerOptions );
break;
}
}
@@ -871,6 +874,7 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit
newLayer->setCustomProperty( CUSTOM_PROPERTY_REMOTE_SOURCE, layer->source() );
newLayer->setCustomProperty( CUSTOM_PROPERTY_REMOTE_PROVIDER, layer->providerType() );
newLayer->setCustomProperty( CUSTOM_PROPERTY_ORIGINAL_LAYERID, layer->id() );
newLayer->setCustomProperty( CUSTOM_PROPERTY_LAYERNAME_SUFFIX, layerNameSuffix );

// register this layer with the central layers registry
QgsProject::instance()->addMapLayers(
@@ -64,8 +64,9 @@ class CORE_EXPORT QgsOfflineEditing : public QObject
* \param layerIds List of layer names to convert
* \param onlySelected Only copy selected features from layers where a selection is present
* \param containerType defines the SQLite file container type like SpatiaLite or GPKG
* \param layerNameSuffix Suffix string added to the offline layer name
*/
bool convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected = false, ContainerType containerType = SpatiaLite );
bool convertToOfflineProject( const QString &offlineDataPath, const QString &offlineDbFile, const QStringList &layerIds, bool onlySelected = false, ContainerType containerType = SpatiaLite, const QString &layerNameSuffix = QStringLiteral( " (offline)" ) );

//! Returns TRUE if current project is offline
bool isOfflineProject() const;
@@ -117,7 +118,7 @@ class CORE_EXPORT QgsOfflineEditing : public QObject
bool createOfflineDb( const QString &offlineDbPath, ContainerType containerType = SpatiaLite );
void createLoggingTables( sqlite3 *db );

QgsVectorLayer *copyVectorLayer( QgsVectorLayer *layer, sqlite3 *db, const QString &offlineDbPath, bool onlySelected, ContainerType containerType = SpatiaLite );
QgsVectorLayer *copyVectorLayer( QgsVectorLayer *layer, sqlite3 *db, const QString &offlineDbPath, bool onlySelected, ContainerType containerType = SpatiaLite, const QString &layerNameSuffix = QStringLiteral( " (offline)" ) );

void applyAttributesAdded( QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId, int commitNo );
void applyFeaturesAdded( QgsVectorLayer *offlineLayer, QgsVectorLayer *remoteLayer, sqlite3 *db, int layerId );
@@ -104,7 +104,7 @@ void QgsOfflineEditingPlugin::convertProject()
}

mProgressDialog->setTitle( tr( "Converting to Offline Project" ) );
if ( mOfflineEditing->convertToOfflineProject( myPluginGui->offlineDataPath(), myPluginGui->offlineDbFile(), selectedLayerIds, myPluginGui->onlySelected(), myPluginGui->dbContainerType() ) )
if ( mOfflineEditing->convertToOfflineProject( myPluginGui->offlineDataPath(), myPluginGui->offlineDbFile(), selectedLayerIds, myPluginGui->onlySelected(), myPluginGui->dbContainerType(), QString() ) )
{
updateActions();
// Redraw, to make the offline layer visible
@@ -52,6 +52,9 @@ class TestQgsOfflineEditing : public QObject
void init(); // will be called before each testfunction is executed.
void cleanup(); // will be called after every testfunction.

void createSpatialiteAndSynchronizeBack_data();
void createGeopackageAndSynchronizeBack_data();

void createSpatialiteAndSynchronizeBack();
void createGeopackageAndSynchronizeBack();
void removeConstraintsOnDefaultValues();
@@ -113,8 +116,36 @@ void TestQgsOfflineEditing::cleanup()
dir.remove( offlineDbFile );
}

void TestQgsOfflineEditing::createSpatialiteAndSynchronizeBack_data()
{
QTest::addColumn<QString>( "suffix_input" );
QTest::addColumn<QString>( "suffix_result" );

QTest::newRow( "no suffix" ) << QString( "no suffix" ) << QStringLiteral( " (offline)" ); //default value expected
QTest::newRow( "null suffix" ) << QString() << QString();
QTest::newRow( "empty suffix" ) << QStringLiteral( "" ) << QStringLiteral( "" );
QTest::newRow( "part of name suffix" ) << QStringLiteral( "point" ) << QStringLiteral( "point" );
QTest::newRow( "another suffix" ) << QStringLiteral( "another suffix" ) << QStringLiteral( "another suffix" );
}

void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack_data()
{
QTest::addColumn<QString>( "suffix_input" );
QTest::addColumn<QString>( "suffix_result" );

QTest::newRow( "no suffix" ) << QStringLiteral( "no suffix" ) << QStringLiteral( " (offline)" ); //default value expected
QTest::newRow( "null suffix" ) << QString() << QString();
QTest::newRow( "empty suffix" ) << QStringLiteral( "" ) << QStringLiteral( "" );
QTest::newRow( "part of name suffix" ) << QStringLiteral( "point" ) << QStringLiteral( "point" );
QTest::newRow( "another suffix" ) << QStringLiteral( "another suffix" ) << QStringLiteral( "another suffix" );
}

void TestQgsOfflineEditing::createSpatialiteAndSynchronizeBack()
{

QFETCH( QString, suffix_input );
QFETCH( QString, suffix_result );

offlineDbFile = "TestQgsOfflineEditing.sqlite";
QCOMPARE( mpLayer->name(), QStringLiteral( "points" ) );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
@@ -125,10 +156,15 @@ void TestQgsOfflineEditing::createSpatialiteAndSynchronizeBack()
layerTreelayer->setCustomProperty( QStringLiteral( "showFeatureCount" ), 1 );

//convert
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::SpatiaLite );
if ( suffix_input.compare( QStringLiteral( "no suffix" ) ) == 0 )
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::SpatiaLite );
else
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::SpatiaLite, suffix_input );

mpLayer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayersByName( QStringLiteral( "points (offline)" ) ).first() );
QCOMPARE( mpLayer->name(), QStringLiteral( "points (offline)" ) );
QString layerName = QStringLiteral( "points%1" ).arg( suffix_result );

mpLayer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayersByName( layerName ).first() );
QCOMPARE( mpLayer->name(), layerName );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
//check LayerTreeNode showFeatureCount property
layerTreelayer = QgsProject::instance()->layerTreeRoot()->findLayer( mpLayer->id() );
@@ -151,6 +187,9 @@ void TestQgsOfflineEditing::createSpatialiteAndSynchronizeBack()

void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack()
{
QFETCH( QString, suffix_input );
QFETCH( QString, suffix_result );

offlineDbFile = "TestQgsOfflineEditing.gpkg";
QCOMPARE( mpLayer->name(), QStringLiteral( "points" ) );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
@@ -171,10 +210,14 @@ void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack()
mpLayer->styleManager()->addStyle( QStringLiteral( "testStyle" ), style );

//convert
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::GPKG );

mpLayer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayersByName( QStringLiteral( "points (offline)" ) ).first() );
QCOMPARE( mpLayer->name(), QStringLiteral( "points (offline)" ) );
if ( suffix_input.compare( QStringLiteral( "no suffix" ) ) == 0 )
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::GPKG );
else
mOfflineEditing->convertToOfflineProject( offlineDataPath, offlineDbFile, layerIds, false, QgsOfflineEditing::GPKG, suffix_input );

QString layerName = QStringLiteral( "points%1" ).arg( suffix_result );
mpLayer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayersByName( layerName ).first() );
QCOMPARE( mpLayer->name(), layerName );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
//comparing with the number +1 because GPKG created an fid
QCOMPARE( mpLayer->fields().size(), numberOfFields + 1 );
@@ -232,7 +275,6 @@ void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack()
QCOMPARE( mpLayer->dataProvider()->featureCount(), numberOfFeatures );
}


void TestQgsOfflineEditing::removeConstraintsOnDefaultValues()
{
offlineDbFile = "TestQgsOfflineEditing.gpkg";

0 comments on commit 6e1b23a

Please sign in to comment.
You can’t perform that action at this time.