Skip to content
Permalink
Browse files

Merge pull request #8600 from signedav/fix_gpkg_order

Offline editing to GPKG attribute order. Fixes #20276
  • Loading branch information
m-kuhn committed Dec 11, 2018
2 parents 54f28df + 8fda2b7 commit bec04c1e44b085db74735da4c15fc8c4af7455fe
Showing with 50 additions and 11 deletions.
  1. +7 −8 src/core/qgsofflineediting.cpp
  2. +43 −3 tests/src/core/testqgsofflineediting.cpp
@@ -762,12 +762,10 @@ QgsVectorLayer *QgsOfflineEditing::copyVectorLayer( QgsVectorLayer *layer, sqlit

// NOTE: SpatiaLite provider ignores position of geometry column
// fill gap in QgsAttributeMap if geometry column is not last (WORKAROUND)
QgsAttributes attrs = f.attributes();
int column = 0;
QgsAttributes attrs = f.attributes();
// on GPKG newAttrs has an addition FID attribute, so we have to add a dummy in the original set
if ( containerType == GPKG )
column++;
QgsAttributes newAttrs( attrs.count() + column );
QgsAttributes newAttrs( containerType == GPKG ? attrs.count() + 1 : attrs.count() );
for ( int it = 0; it < attrs.count(); ++it )
{
newAttrs[column++] = attrs.at( it );
@@ -1139,13 +1137,14 @@ void QgsOfflineEditing::updateLayerOrder( QgsVectorLayer *sourceLayer, QgsVector
QMap<int, int> QgsOfflineEditing::attributeLookup( QgsVectorLayer *offlineLayer, QgsVectorLayer *remoteLayer )
{
const QgsAttributeList &offlineAttrs = offlineLayer->attributeList();
const QgsAttributeList &remoteAttrs = remoteLayer->attributeList();

QMap < int /*offline attr*/, int /*remote attr*/ > attrLookup;
// NOTE: use size of remoteAttrs, as offlineAttrs can have new attributes not yet synced
for ( int i = 0; i < remoteAttrs.size(); i++ )
// NOTE: though offlineAttrs can have new attributes not yet synced, we take the amount of offlineAttrs
// because we anyway only add mapping for the fields existing in remoteLayer (this because it could contain fid on 0)
for ( int i = 0; i < offlineAttrs.size(); i++ )
{
attrLookup.insert( offlineAttrs.at( i ), remoteAttrs.at( i ) );
if ( remoteLayer->fields().lookupField( offlineLayer->fields().field( i ).name() ) >= 0 )
attrLookup.insert( offlineAttrs.at( i ), remoteLayer->fields().indexOf( offlineLayer->fields().field( i ).name() ) );
}

return attrLookup;
@@ -41,6 +41,7 @@ class TestQgsOfflineEditing : public QObject
QStringList layerIds;
long numberOfFeatures;
int numberOfFields;
QTemporaryDir tempDir;

private slots:
void initTestCase();// will be called before the first testfunction is executed.
@@ -75,8 +76,12 @@ void TestQgsOfflineEditing::cleanupTestCase()
void TestQgsOfflineEditing::init()
{
QString myFileName( TEST_DATA_DIR ); //defined in CmakeLists.txt
myFileName = myFileName + "/points.shp";
QFileInfo myMapFileInfo( myFileName );
QString myTempDirName = tempDir.path();
QFile::copy( myFileName + "/points.shp", myTempDirName + "/points.shp" );
QFile::copy( myFileName + "/points.shx", myTempDirName + "/points.shx" );
QFile::copy( myFileName + "/points.dbf", myTempDirName + "/points.dbf" );
QString myTempFileName = myTempDirName + "/points.shp";
QFileInfo myMapFileInfo( myTempFileName );
mpLayer = new QgsVectorLayer( myMapFileInfo.filePath(),
myMapFileInfo.completeBaseName(), QStringLiteral( "ogr" ) );
QgsProject::instance()->addMapLayer( mpLayer );
@@ -124,6 +129,9 @@ void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack()
QCOMPARE( mpLayer->name(), QStringLiteral( "points" ) );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
QCOMPARE( mpLayer->fields().size(), numberOfFields );
QgsFeature firstFeatureBeforeAction;
QgsFeatureIterator it = mpLayer->getFeatures();
it.nextFeature( firstFeatureBeforeAction );

connect( mOfflineEditing, &QgsOfflineEditing::warning, this, []( const QString & title, const QString & message ) { qDebug() << title << message; } );
//convert
@@ -135,13 +143,45 @@ void TestQgsOfflineEditing::createGeopackageAndSynchronizeBack()
//comparing with the number +1 because GPKG created an fid
QCOMPARE( mpLayer->fields().size(), numberOfFields + 1 );

QgsFeature firstFeatureInAction;
it = mpLayer->getFeatures();
it.nextFeature( firstFeatureInAction );

//compare some values
QCOMPARE( firstFeatureInAction.attribute( QStringLiteral( "Class" ) ).toString(), firstFeatureBeforeAction.attribute( QStringLiteral( "Class" ) ).toString() );
QCOMPARE( firstFeatureInAction.attribute( QStringLiteral( "Heading" ) ).toString(), firstFeatureBeforeAction.attribute( QStringLiteral( "Heading" ) ).toString() );
QCOMPARE( firstFeatureInAction.attribute( QStringLiteral( "Cabin Crew" ) ).toString(), firstFeatureBeforeAction.attribute( QStringLiteral( "Cabin Crew" ) ).toString() );

QgsFeature newFeature( mpLayer->dataProvider()->fields() );
newFeature.setAttribute( QStringLiteral( "Class" ), QStringLiteral( "Superjet" ) );
mpLayer->startEditing();
mpLayer->addFeature( newFeature );
mpLayer->commitChanges();
QCOMPARE( mpLayer->featureCount(), numberOfFeatures + 1 );

//synchronize back
mOfflineEditing->synchronize();

mpLayer = qobject_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayers().first() );
QCOMPARE( mpLayer->name(), QStringLiteral( "points" ) );
QCOMPARE( mpLayer->featureCount(), numberOfFeatures );
QCOMPARE( mpLayer->dataProvider()->featureCount(), numberOfFeatures + 1 );
QCOMPARE( mpLayer->fields().size(), numberOfFields );
//get last feature
QgsFeature f = mpLayer->getFeature( mpLayer->dataProvider()->featureCount() - 1 );
qDebug() << "FID:" << f.id() << "Class:" << f.attribute( "Class" ).toString();
QCOMPARE( f.attribute( QStringLiteral( "Class" ) ).toString(), QStringLiteral( "Superjet" ) );

QgsFeature firstFeatureAfterAction;
it = mpLayer->getFeatures();
it.nextFeature( firstFeatureAfterAction );

QCOMPARE( firstFeatureAfterAction, firstFeatureBeforeAction );

//and delete the feature again
QgsFeatureIds idsToClean;
idsToClean << f.id();
mpLayer->dataProvider()->deleteFeatures( idsToClean );
QCOMPARE( mpLayer->dataProvider()->featureCount(), numberOfFeatures );
}

QGSTEST_MAIN( TestQgsOfflineEditing )

0 comments on commit bec04c1

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