From 5db95e3a4d2c6d4811c58d0c7b6d9a6aeb9aae20 Mon Sep 17 00:00:00 2001 From: Julien Cabieces Date: Wed, 8 Dec 2021 11:40:50 +0100 Subject: [PATCH] Fixes #45872 : resolveReference after we load/create embedded group --- src/app/qgisapp.cpp | 77 +- src/app/qgisapp.h | 10 + src/core/project/qgsproject.cpp | 8 +- tests/src/app/testqgisapp.cpp | 18 + tests/src/core/testqgsproject.cpp | 14 + tests/testdata/embedded_groups/joins1.qgs | 823 ++++++++++++++++++++++ tests/testdata/embedded_groups/joins2.qgz | Bin 0 -> 2868 bytes 7 files changed, 912 insertions(+), 38 deletions(-) create mode 100644 tests/testdata/embedded_groups/joins1.qgs create mode 100644 tests/testdata/embedded_groups/joins2.qgz diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index c7ef96a1237..fe112c1b644 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -13607,52 +13607,61 @@ void QgisApp::addMapLayer( QgsMapLayer *mapLayer ) } } + void QgisApp::embedLayers() { //dialog to select groups/layers from other project files QgsProjectLayerGroupDialog d( this ); if ( d.exec() == QDialog::Accepted && d.isValid() ) { - QgsCanvasRefreshBlocker refreshBlocker; + addEmbeddedItems( d.selectedProjectFile(), d.selectedGroups(), d.selectedLayerIds() ); + } +} - QString projectFile = d.selectedProjectFile(); +void QgisApp::addEmbeddedItems( const QString &projectFile, const QStringList &groups, const QStringList &layerIds ) +{ + QgsCanvasRefreshBlocker refreshBlocker; - //groups - QStringList groups = d.selectedGroups(); - QStringList::const_iterator groupIt = groups.constBegin(); - for ( ; groupIt != groups.constEnd(); ++groupIt ) + //groups + QStringList::const_iterator groupIt = groups.constBegin(); + for ( ; groupIt != groups.constEnd(); ++groupIt ) + { + QgsLayerTreeGroup *newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile, QStringList() ); + + if ( newGroup ) + QgsProject::instance()->layerTreeRoot()->addChildNode( newGroup ); + } + + //layer ids + QList brokenNodes; + + // resolve dependencies + QgsLayerDefinition::DependencySorter depSorter( projectFile ); + QStringList sortedIds = depSorter.sortedLayerIds(); + const auto constSortedIds = sortedIds; + for ( const QString &id : constSortedIds ) + { + const auto constLayerIds = layerIds; + for ( const QString &selId : constLayerIds ) { - QgsLayerTreeGroup *newGroup = QgsProject::instance()->createEmbeddedGroup( *groupIt, projectFile, QStringList() ); - - if ( newGroup ) - QgsProject::instance()->layerTreeRoot()->addChildNode( newGroup ); + if ( selId == id ) + QgsProject::instance()->createEmbeddedLayer( selId, projectFile, brokenNodes ); } + } - //layer ids - QList brokenNodes; + // fix broken relations and dependencies + for ( const QString &id : constSortedIds ) + { + QgsVectorLayer *vlayer = qobject_cast( QgsProject::instance()->mapLayer( id ) ); + if ( vlayer ) + vectorLayerStyleLoaded( vlayer, QgsMapLayer::AllStyleCategories ); + } - // resolve dependencies - QgsLayerDefinition::DependencySorter depSorter( projectFile ); - QStringList sortedIds = depSorter.sortedLayerIds(); - QStringList layerIds = d.selectedLayerIds(); - const auto constSortedIds = sortedIds; - for ( const QString &id : constSortedIds ) - { - const auto constLayerIds = layerIds; - for ( const QString &selId : constLayerIds ) - { - if ( selId == id ) - QgsProject::instance()->createEmbeddedLayer( selId, projectFile, brokenNodes ); - } - } - - // fix broken relations and dependencies - for ( const QString &id : constSortedIds ) - { - QgsVectorLayer *vlayer = qobject_cast( QgsProject::instance()->mapLayer( id ) ); - if ( vlayer ) - vectorLayerStyleLoaded( vlayer, QgsMapLayer::AllStyleCategories ); - } + // Resolve references to other layers + QMap layers = QgsProject::instance()->mapLayers(); + for ( QMap::iterator it = layers.begin(); it != layers.end(); ++it ) + { + it.value()->resolveReferences( QgsProject::instance() ); } } diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 348d424f014..30a941bac0c 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -1558,8 +1558,17 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow void showMeshCalculator(); //! Open dialog to align raster layers void showAlignRasterTool(); + + /** + * Called whenever user wants to embed layers + */ void embedLayers(); + /** + * Embed \a groups and \a layerIds items from \a projectFile + */ + void addEmbeddedItems( const QString &projectFile, const QStringList &groups, const QStringList &layerIds ); + //! Creates a new map canvas view void newMapCanvas(); //! Creates a new 3D map canvas view @@ -2733,6 +2742,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow friend class QgsCanvasRefreshBlocker; friend class TestQgisAppPython; + friend class TestQgisApp; friend class QgisAppInterface; friend class QgsAppScreenShots; }; diff --git a/src/core/project/qgsproject.cpp b/src/core/project/qgsproject.cpp index 78ee1b60c0e..788e4872a3c 100644 --- a/src/core/project/qgsproject.cpp +++ b/src/core/project/qgsproject.cpp @@ -1640,6 +1640,10 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags mMainAnnotationLayer->readLayerXml( doc->documentElement().firstChildElement( QStringLiteral( "main-annotation-layer" ) ), context ); mMainAnnotationLayer->setTransformContext( mTransformContext ); + // load embedded groups and layers + profile.switchTask( tr( "Loading embedded layers" ) ); + loadEmbeddedNodes( mRootGroup, flags ); + // Resolve references to other layers // Needs to be done here once all dependent layers are loaded profile.switchTask( tr( "Resolving layer references" ) ); @@ -1651,10 +1655,6 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags mLayerTreeRegistryBridge->setEnabled( true ); - // load embedded groups and layers - profile.switchTask( tr( "Loading embedded layers" ) ); - loadEmbeddedNodes( mRootGroup, flags ); - // now that layers are loaded, we can resolve layer tree's references to the layers profile.switchTask( tr( "Resolving references" ) ); mRootGroup->resolveReferences( this ); diff --git a/tests/src/app/testqgisapp.cpp b/tests/src/app/testqgisapp.cpp index d84a2c79897..657837ae762 100644 --- a/tests/src/app/testqgisapp.cpp +++ b/tests/src/app/testqgisapp.cpp @@ -42,6 +42,7 @@ class TestQgisApp : public QObject void addVectorLayerGeopackageSingleLayer(); void addVectorLayerGeopackageSingleLayerAlreadyLayername(); void addVectorLayerInvalid(); + void addEmbeddedGroup(); private: QgisApp *mQgisApp = nullptr; @@ -137,5 +138,22 @@ void TestQgisApp::addVectorLayerInvalid() QVERIFY( !layer ); } +void TestQgisApp::addEmbeddedGroup() +{ + const QString projectPath = QString( TEST_DATA_DIR ) + QStringLiteral( "/embedded_groups/joins1.qgs" ); + + QCOMPARE( QgsProject::instance()->layers().count(), 0 ); + + mQgisApp->addEmbeddedItems( projectPath, QStringList() << QStringLiteral( "GROUP" ), QStringList() ); + + QgsVectorLayer *vl = QgsProject::instance()->mapLayer( QStringLiteral( "polys_with_id_32002f94_eebe_40a5_a182_44198ba1bc5a" ) ); + QCOMPARE( vl->fields().count(), 5 ); + + // cleanup + QgsProject::instance()->clear(); +} + + + QGSTEST_MAIN( TestQgisApp ) #include "testqgisapp.moc" diff --git a/tests/src/core/testqgsproject.cpp b/tests/src/core/testqgsproject.cpp index 051cb58915c..87c31fe752a 100644 --- a/tests/src/core/testqgsproject.cpp +++ b/tests/src/core/testqgsproject.cpp @@ -59,6 +59,7 @@ class TestQgsProject : public QObject void testAttachmentsQgs(); void testAttachmentsQgz(); void testAttachmentIdentifier(); + void testEmbeddedGroupWithJoins(); }; void TestQgsProject::init() @@ -906,5 +907,18 @@ void TestQgsProject::testAttachmentIdentifier() } +void TestQgsProject::testEmbeddedGroupWithJoins() +{ + const QString projectPath = QString( TEST_DATA_DIR ) + QStringLiteral( "/embedded_groups/joins2.qgz" ); + QgsProject p; + p.read( projectPath ); + + QCOMPARE( p.layers().count(), 2 ); + + QgsVectorLayer *vl = p.mapLayer( QStringLiteral( "polys_with_id_32002f94_eebe_40a5_a182_44198ba1bc5a" ) ); + QCOMPARE( vl->fields().count(), 5 ); +} + + QGSTEST_MAIN( TestQgsProject ) #include "testqgsproject.moc" diff --git a/tests/testdata/embedded_groups/joins1.qgs b/tests/testdata/embedded_groups/joins1.qgs new file mode 100644 index 00000000000..b94f6a707ef --- /dev/null +++ b/tests/testdata/embedded_groups/joins1.qgs @@ -0,0 +1,823 @@ + + + + + + + + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + + + + + + + + + + polys_with_id_32002f94_eebe_40a5_a182_44198ba1bc5a + polys_overlapping_with_id_3c22a7a0_06b3_4ff5_a2f8_332bafa241bd + + + + + + + + + + + + degrees + + -119.80118356386469713 + 23.95241214538275187 + -82.91169073314071625 + 47.28163022407258609 + + 0 + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + 0 + + + + + + + + + + + + + + + + Annotations_d365fe16_031e_4beb_8157_5b1a54d7f109 + + + + + + + + + + 0 + 0 + + + + + false + + + + + + + + + + + + + + + + + 0 + 0 + + + + + false + + + + + + 1 + 0 + + + + + + -118.92286230599032137 + 24.50786971868489061 + -83.79001199101509201 + 46.72617265077044379 + + + -118.92286230599032137 + 24.50786971868489061 + -83.79001199101509201 + 46.72617265077044379 + + polys_overlapping_with_id_3c22a7a0_06b3_4ff5_a2f8_332bafa241bd + ../polys_overlapping_with_id.shp + + + + polys_overlapping_with_id + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + dataset + + + + + + + + + + 0 + 0 + + + + + false + + + + + ogr + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + "Name" + + + + + -118.92286230599032137 + 24.50786971868489061 + -83.79001199101509201 + 46.72617265077044379 + + + -118.92286230599032137 + 24.50786971868489061 + -83.79001199101509201 + 46.72617265077044379 + + polys_with_id_32002f94_eebe_40a5_a182_44198ba1bc5a + ../polys_with_id.shp + + + + polys_with_id + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + dataset + + + + + + + + + + 0 + 0 + + + + + false + + + + + ogr + + + + + + + + + + + + + 1 + 1 + 1 + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + 0 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + 0 + generatedlayout + + + + + + Name + + + + + + + + + + 2 + + + 255 + 255 + 255 + 255 + 0 + 255 + 255 + + + false + + + + + + + 50 + 5 + 16 + 30 + 2.5 + true + false + false + 0 + 0 + false + false + true + 0 + 255,0,0,255 + + + false + + + true + 2 + + + 3452 + +proj=longlat +datum=WGS84 +no_defs + EPSG:4326 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + GEOGCRS["WGS 84",DATUM["World Geodetic System 1984",ELLIPSOID["WGS 84",6378137,298.257223563,LENGTHUNIT["metre",1]]],PRIMEM["Greenwich",0,ANGLEUNIT["degree",0.0174532925199433]],CS[ellipsoidal,2],AXIS["geodetic latitude (Lat)",north,ORDER[1],ANGLEUNIT["degree",0.0174532925199433]],AXIS["geodetic longitude (Lon)",east,ORDER[2],ANGLEUNIT["degree",0.0174532925199433]],USAGE[SCOPE["Horizontal component of 3D system."],AREA["World."],BBOX[-90,-180,90,180]],ID["EPSG",4326]] + +proj=longlat +datum=WGS84 +no_defs + 3452 + 4326 + EPSG:4326 + WGS 84 + longlat + EPSG:7030 + true + + + + + + + + + + diff --git a/tests/testdata/embedded_groups/joins2.qgz b/tests/testdata/embedded_groups/joins2.qgz new file mode 100644 index 0000000000000000000000000000000000000000..c3c67131f038ae0c45dd2d2c66990c186b4f9c89 GIT binary patch literal 2868 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 S0096205|{u0Okq+0002mplNde literal 0 HcmV?d00001