diff --git a/python/core/auto_additions/qgsproject.py b/python/core/auto_additions/qgsproject.py index 8d67d60b9bd..7882645d9db 100644 --- a/python/core/auto_additions/qgsproject.py +++ b/python/core/auto_additions/qgsproject.py @@ -12,7 +12,10 @@ QgsProject.ReadFlag.FlagTrustLayerMetadata.__doc__ = "Trust layer metadata. Impr QgsProject.FlagDontStoreOriginalStyles = QgsProject.ReadFlag.FlagDontStoreOriginalStyles QgsProject.FlagDontStoreOriginalStyles.is_monkey_patched = True QgsProject.ReadFlag.FlagDontStoreOriginalStyles.__doc__ = "Skip the initial XML style storage for layers. Useful for minimising project load times in non-interactive contexts." -QgsProject.ReadFlag.__doc__ = 'Flags which control project read behavior.\n\n.. versionadded:: 3.10\n\n' + '* ``FlagDontResolveLayers``: ' + QgsProject.ReadFlag.FlagDontResolveLayers.__doc__ + '\n' + '* ``FlagDontLoadLayouts``: ' + QgsProject.ReadFlag.FlagDontLoadLayouts.__doc__ + '\n' + '* ``FlagTrustLayerMetadata``: ' + QgsProject.ReadFlag.FlagTrustLayerMetadata.__doc__ + '\n' + '* ``FlagDontStoreOriginalStyles``: ' + QgsProject.ReadFlag.FlagDontStoreOriginalStyles.__doc__ +QgsProject.FlagDontLoad3DViews = QgsProject.ReadFlag.FlagDontLoad3DViews +QgsProject.FlagDontLoad3DViews.is_monkey_patched = True +QgsProject.ReadFlag.FlagDontLoad3DViews.__doc__ = "" +QgsProject.ReadFlag.__doc__ = 'Flags which control project read behavior.\n\n.. versionadded:: 3.10\n\n' + '* ``FlagDontResolveLayers``: ' + QgsProject.ReadFlag.FlagDontResolveLayers.__doc__ + '\n' + '* ``FlagDontLoadLayouts``: ' + QgsProject.ReadFlag.FlagDontLoadLayouts.__doc__ + '\n' + '* ``FlagTrustLayerMetadata``: ' + QgsProject.ReadFlag.FlagTrustLayerMetadata.__doc__ + '\n' + '* ``FlagDontStoreOriginalStyles``: ' + QgsProject.ReadFlag.FlagDontStoreOriginalStyles.__doc__ + '\n' + '* ``FlagDontLoad3DViews``: ' + QgsProject.ReadFlag.FlagDontLoad3DViews.__doc__ # -- # monkey patching scoped based enum QgsProject.FileFormat.Qgz.__doc__ = "Archive file format, supports auxiliary data" diff --git a/python/core/auto_generated/project/qgsproject.sip.in b/python/core/auto_generated/project/qgsproject.sip.in index 81d1054e3d2..bd4b9d62cf8 100644 --- a/python/core/auto_generated/project/qgsproject.sip.in +++ b/python/core/auto_generated/project/qgsproject.sip.in @@ -15,7 +15,6 @@ - class QgsProject : QObject, QgsExpressionContextGenerator, QgsExpressionContextScopeGenerator, QgsProjectTranslator { %Docstring(signature="appended") @@ -43,6 +42,7 @@ open within the main QGIS application. FlagDontLoadLayouts, FlagTrustLayerMetadata, FlagDontStoreOriginalStyles, + FlagDontLoad3DViews, }; typedef QFlags ReadFlags; @@ -745,6 +745,15 @@ the project. %End + Qgs3DViewsManager *views3DManager(); +%Docstring +Returns the project's 3D views manager, which manages 3D views +in the project. + +.. versionadded:: 3.24 +%End + + QgsBookmarkManager *bookmarkManager(); %Docstring Returns the project's bookmark manager, which manages bookmarks within diff --git a/src/app/3d/qgs3dviewsmanager.cpp b/src/app/3d/qgs3dviewsmanagerdialog.cpp similarity index 69% rename from src/app/3d/qgs3dviewsmanager.cpp rename to src/app/3d/qgs3dviewsmanagerdialog.cpp index 28a40702d98..1acdb0d60bd 100644 --- a/src/app/3d/qgs3dviewsmanager.cpp +++ b/src/app/3d/qgs3dviewsmanagerdialog.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - qgs3dviewsmanager.cpp + qgs3dviewsmanagerdialog.cpp -------------------------------------- Date : December 2021 Copyright : (C) 2021 by Belgacem Nedjima @@ -13,14 +13,15 @@ * * ***************************************************************************/ -#include "qgs3dviewsmanager.h" +#include "qgs3dviewsmanagerdialog.h" #include "qgisapp.h" #include "qgs3dmapcanvasdockwidget.h" #include "qgsnewnamedialog.h" #include "qgs3dmapcanvas.h" +#include "qgs3dviewsmanager.h" -Qgs3DViewsManager::Qgs3DViewsManager( QWidget *parent, Qt::WindowFlags f ) +Qgs3DViewsManagerDialog::Qgs3DViewsManagerDialog( QWidget *parent, Qt::WindowFlags f ) : QDialog( parent, f ) { setupUi( this ); @@ -31,19 +32,27 @@ Qgs3DViewsManager::Qgs3DViewsManager( QWidget *parent, Qt::WindowFlags f ) m3DViewsListView->setEditTriggers( QAbstractItemView::NoEditTriggers ); m3DViewsListView->setSelectionMode( QAbstractItemView::SingleSelection ); - connect( mOpenButton, &QToolButton::clicked, this, &Qgs3DViewsManager::openClicked ); - connect( mDuplicateButton, &QToolButton::clicked, this, &Qgs3DViewsManager::duplicateClicked ); - connect( mRemoveButton, &QToolButton::clicked, this, &Qgs3DViewsManager::removeClicked ); - connect( mRenameButton, &QToolButton::clicked, this, &Qgs3DViewsManager::renameClicked ); + connect( mOpenButton, &QToolButton::clicked, this, &Qgs3DViewsManagerDialog::openClicked ); + connect( mDuplicateButton, &QToolButton::clicked, this, &Qgs3DViewsManagerDialog::duplicateClicked ); + connect( mRemoveButton, &QToolButton::clicked, this, &Qgs3DViewsManagerDialog::removeClicked ); + connect( mRenameButton, &QToolButton::clicked, this, &Qgs3DViewsManagerDialog::renameClicked ); + + connect( QgsProject::instance()->views3DManager(), &Qgs3DViewsManager::viewsListChanged, this, &Qgs3DViewsManagerDialog::onViewsListChanged ); } -void Qgs3DViewsManager::openClicked() +void Qgs3DViewsManagerDialog::onViewsListChanged() +{ + reload(); +} + +void Qgs3DViewsManagerDialog::openClicked() { if ( m3DViewsListView->selectionModel()->selectedRows().isEmpty() ) return; QString viewName = m3DViewsListView->selectionModel()->selectedRows().at( 0 ).data( Qt::DisplayRole ).toString(); - Qgs3DMapCanvasDockWidget *widget = m3DMapViewsWidgets->value( viewName, nullptr ); + + Qgs3DMapCanvasDockWidget *widget = QgisApp::instance()->findChild( viewName ); if ( !widget ) { widget = QgisApp::instance()->open3DMapView( viewName ); @@ -56,7 +65,7 @@ void Qgs3DViewsManager::openClicked() } } -void Qgs3DViewsManager::duplicateClicked() +void Qgs3DViewsManagerDialog::duplicateClicked() { if ( m3DViewsListView->selectionModel()->selectedRows().isEmpty() ) return; @@ -65,25 +74,21 @@ void Qgs3DViewsManager::duplicateClicked() QString newViewName = askUserForATitle( existingViewName, tr( "Duplicate" ), false ); QgisApp::instance()->duplicate3DMapView( existingViewName, newViewName ); - reload(); } -void Qgs3DViewsManager::removeClicked() +void Qgs3DViewsManagerDialog::removeClicked() { if ( m3DViewsListView->selectionModel()->selectedRows().isEmpty() ) return; QString viewName = m3DViewsListView->selectionModel()->selectedRows().at( 0 ).data( Qt::DisplayRole ).toString(); - m3DMapViewsDom->remove( viewName ); - if ( Qgs3DMapCanvasDockWidget *w = m3DMapViewsWidgets->value( viewName, nullptr ) ) - { - m3DMapViewsWidgets->remove( viewName ); + + QgsProject::instance()->views3DManager()->remove3DView( viewName ); + if ( Qgs3DMapCanvasDockWidget *w = QgisApp::instance()->findChild( viewName + QStringLiteral( "ViewObject" ) ) ) w->close(); - } - reload(); } -void Qgs3DViewsManager::renameClicked() +void Qgs3DViewsManagerDialog::renameClicked() { if ( m3DViewsListView->selectionModel()->selectedRows().isEmpty() ) return; @@ -94,45 +99,25 @@ void Qgs3DViewsManager::renameClicked() if ( newTitle.isEmpty() ) return; - QDomElement dom = m3DMapViewsDom->value( oldTitle ); + QgsProject::instance()->views3DManager()->rename3DView( oldTitle, newTitle ); - m3DMapViewsDom->remove( oldTitle ); - m3DMapViewsDom->insert( newTitle, dom ); - - if ( Qgs3DMapCanvasDockWidget *widget = m3DMapViewsWidgets->value( oldTitle, nullptr ) ) + if ( Qgs3DMapCanvasDockWidget *widget = QgisApp::instance()->findChild( oldTitle + QStringLiteral( "ViewObject" ) ) ) { - m3DMapViewsWidgets->remove( oldTitle ); - m3DMapViewsWidgets->insert( newTitle, widget ); widget->setWindowTitle( newTitle ); widget->mapCanvas3D()->setObjectName( newTitle ); } - reload(); } -void Qgs3DViewsManager::reload() +void Qgs3DViewsManagerDialog::reload() { - if ( !m3DMapViewsDom || !m3DMapViewsWidgets ) - return; - - mListModel->setStringList( m3DMapViewsDom->keys() ); + QStringList names = QgsProject::instance()->views3DManager()->get3DViewsNames(); + mListModel->setStringList( names ); } -void Qgs3DViewsManager::set3DMapViewsDom( QMap &mapViews3DDom ) -{ - m3DMapViewsDom = &mapViews3DDom; - reload(); -} - -void Qgs3DViewsManager::set3DMapViewsWidgets( QMap &mapViews3DWidgets ) -{ - m3DMapViewsWidgets = &mapViews3DWidgets; - reload(); -} - -QString Qgs3DViewsManager::askUserForATitle( QString oldTitle, QString action, bool allowExistingTitle ) +QString Qgs3DViewsManagerDialog::askUserForATitle( QString oldTitle, QString action, bool allowExistingTitle ) { QString newTitle = oldTitle; - QStringList notAllowedTitles = m3DMapViewsDom->keys(); + QStringList notAllowedTitles = mListModel->stringList(); if ( allowExistingTitle ) notAllowedTitles.removeOne( oldTitle ); QgsNewNameDialog dlg( tr( "3D view" ), newTitle, QStringList(), notAllowedTitles, Qt::CaseSensitive, this ); diff --git a/src/app/3d/qgs3dviewsmanager.h b/src/app/3d/qgs3dviewsmanagerdialog.h similarity index 70% rename from src/app/3d/qgs3dviewsmanager.h rename to src/app/3d/qgs3dviewsmanagerdialog.h index 78bdf85a2b6..0d3579551f5 100644 --- a/src/app/3d/qgs3dviewsmanager.h +++ b/src/app/3d/qgs3dviewsmanagerdialog.h @@ -13,10 +13,10 @@ * * ***************************************************************************/ -#ifndef QGS3DVIEWSMANAGER_H -#define QGS3DVIEWSMANAGER_H +#ifndef QGS3DVIEWSMANAGERDIALOG_H +#define QGS3DVIEWSMANAGERDIALOG_H -#include "ui_qgs3dviewsmanager.h" +#include "ui_qgs3dviewsmanagerdialog.h" #include #include @@ -24,28 +24,25 @@ class Qgs3DMapCanvasDockWidget; -class Qgs3DViewsManager : public QDialog, private Ui::Qgs3DViewsManager +class Qgs3DViewsManagerDialog : public QDialog, private Ui::Qgs3DViewsManagerDialog { Q_OBJECT public: - explicit Qgs3DViewsManager( QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags() ); + explicit Qgs3DViewsManagerDialog( QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags() ); void reload(); - void set3DMapViewsDom( QMap &mapViews3DDom ); - void set3DMapViewsWidgets( QMap &mapViews3DWidgets ); private slots: void openClicked(); void duplicateClicked(); void removeClicked(); void renameClicked(); + + void onViewsListChanged(); private: QStringListModel *mListModel = nullptr; - QMap *m3DMapViewsDom = nullptr; - QMap *m3DMapViewsWidgets = nullptr; - QString askUserForATitle( QString oldTitle, QString action, bool allowExistingTitle ); }; diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index bf30a66b015..a56f00d8e8b 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -326,7 +326,7 @@ if (WITH_3D) 3d/qgsshadowrenderingsettingswidget.cpp 3d/qgspointcloud3dsymbolwidget.cpp 3d/qgspointcloudlayer3drendererwidget.cpp - 3d/qgs3dviewsmanager.cpp + 3d/qgs3dviewsmanagerdialog.cpp ) endif() diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 413d5dfbb71..f9c58e0565d 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -136,7 +136,6 @@ #include "qgs3dapputils.h" #include "qgs3doptions.h" #include "qgs3dviewsmanager.h" -#include #endif #ifdef HAVE_GEOREFERENCER @@ -9900,15 +9899,23 @@ Qgs3DMapCanvasDockWidget *QgisApp::open3DMapView( const QString &mapName ) QgsReadWriteContext readWriteContext; readWriteContext.setPathResolver( QgsProject::instance()->pathResolver() ); + QDomElement elem3DMap = QgsProject::instance()->views3DManager()->get3DViewSettings( mapName ); + + if ( elem3DMap.isNull() ) + return nullptr; + Qgs3DMapCanvasDockWidget *mapCanvasDock3D = createNew3DMapCanvasDock( mapName ); if ( !mapCanvasDock3D ) return nullptr; - QDomElement elem3DMap = m3DMapViewsDom[ mapName ]; read3DMapViewSettings( mapCanvasDock3D, elem3DMap ); - m3DMapViewsDom[ mapName ] = elem3DMap; - m3DMapViewsWidgets[ mapName ] = mapCanvasDock3D; + QgsProject::instance()->views3DManager()->viewOpened( mapName ); + + connect( mapCanvasDock3D, &Qgs3DMapCanvasDockWidget::closed, [ &, mapName]() + { + QgsProject::instance()->views3DManager()->viewClosed( mapName ); + } ); return mapCanvasDock3D; #else @@ -9935,9 +9942,8 @@ Qgs3DMapCanvasDockWidget *QgisApp::duplicate3DMapView( const QString &existingVi // If the 3D view is open, copy its configuration to the duplicate widget, otherwise just use the recorded // settings from m3DMapViewsWidgets - if ( Qgs3DMapCanvasDockWidget *w = m3DMapViewsWidgets.value( existingViewName, nullptr ) ) + if ( Qgs3DMapCanvasDockWidget *w = findChild( existingViewName + QStringLiteral( "ViewObject" ) ) ) { - setupDockWidget( mapCanvasDock3D, true ); Qgs3DMapSettings *map = new Qgs3DMapSettings( *w->mapCanvas3D()->map() ); mapCanvasDock3D->setMapSettings( map ); @@ -9954,16 +9960,18 @@ Qgs3DMapCanvasDockWidget *QgisApp::duplicate3DMapView( const QString &existingVi Qgs3DMapSettings *map = new Qgs3DMapSettings; mapCanvasDock3D->setMapSettings( map ); - read3DMapViewSettings( mapCanvasDock3D, m3DMapViewsDom[ existingViewName ] ); + QDomElement elem = QgsProject::instance()->views3DManager()->get3DViewSettings( existingViewName ); + read3DMapViewSettings( mapCanvasDock3D, elem ); } - m3DMapViewsWidgets[ newViewName ] = mapCanvasDock3D; + setupDockWidget( mapCanvasDock3D, true ); QDomElement elem3DMap; elem3DMap = doc.createElement( QStringLiteral( "view" ) ); write3DMapViewSettings( mapCanvasDock3D, doc, elem3DMap ); - m3DMapViewsDom[ newViewName ] = elem3DMap; + QgsProject::instance()->views3DManager()->register3DViewSettings( newViewName, elem3DMap ); + QgsProject::instance()->views3DManager()->viewOpened( newViewName ); return mapCanvasDock3D; #else @@ -10064,7 +10072,7 @@ void QgisApp::populate3DMapviewsMenu( QMenu *menu ) #ifdef HAVE_3D menu->clear(); QList acts; - const QList< QString > views = m3DMapViewsDom.keys(); + const QList< QString > views = QgsProject::instance()->views3DManager()->get3DViewsNames(); acts.reserve( views.size() ); for ( QString viewName : views ) { @@ -13618,11 +13626,7 @@ void QgisApp::showLayoutManager() void QgisApp::show3DMapViewsManager() { #ifdef HAVE_3D - QWidget *dialog = static_cast< QgsAppWindowManager * >( QgsGui::windowManager() )->openApplicationDialog( QgsAppWindowManager::Dialog3DMapViewsManager ); - Qgs3DViewsManager *manager = dynamic_cast< Qgs3DViewsManager *>( dialog ); - manager->set3DMapViewsDom( m3DMapViewsDom ); - manager->set3DMapViewsWidgets( m3DMapViewsWidgets ); - manager->show(); + static_cast< QgsAppWindowManager * >( QgsGui::windowManager() )->openApplicationDialog( QgsAppWindowManager::Dialog3DMapViewsManager ); #endif } @@ -13931,17 +13935,12 @@ Qgs3DMapCanvasDockWidget *QgisApp::createNew3DMapCanvasDock( const QString &name markDirty(); Qgs3DMapCanvasDockWidget *map3DWidget = new Qgs3DMapCanvasDockWidget( this ); + map3DWidget->setObjectName( name + QStringLiteral( "ViewObject" ) ); map3DWidget->setAllowedAreas( Qt::AllDockWidgetAreas ); map3DWidget->setWindowTitle( name ); map3DWidget->mapCanvas3D()->setObjectName( name ); map3DWidget->setMainCanvas( mMapCanvas ); map3DWidget->mapCanvas3D()->setTemporalController( mTemporalControllerWidget->temporalController() ); - m3DMapViewsWidgets[ name ] = map3DWidget; - - connect( map3DWidget, &Qgs3DMapCanvasDockWidget::closed, [ &, name]() - { - m3DMapViewsWidgets.remove( name ); - } ); return map3DWidget; #else @@ -14052,8 +14051,14 @@ void QgisApp::new3DMapCanvas() elem3DMap.setAttribute( QStringLiteral( "isOpen" ), 1 ); write3DMapViewSettings( dock, doc, elem3DMap ); - m3DMapViewsDom[ name ] = elem3DMap; - m3DMapViewsWidgets[ name ] = dock; + + QgsProject::instance()->views3DManager()->register3DViewSettings( name, elem3DMap ); + QgsProject::instance()->views3DManager()->viewOpened( name ); + + connect( dock, &Qgs3DMapCanvasDockWidget::closed, [ &, name]() + { + QgsProject::instance()->views3DManager()->viewClosed( name ); + } ); } #endif } @@ -16748,27 +16753,16 @@ void QgisApp::writeProject( QDomDocument &doc ) qgisNode.appendChild( mapViewNode ); #ifdef HAVE_3D - QgsReadWriteContext readWriteContext; - readWriteContext.setPathResolver( QgsProject::instance()->pathResolver() ); - QDomElement elem3DMaps = doc.createElement( QStringLiteral( "mapViewDocks3D" ) ); - for ( QString viewName : m3DMapViewsDom.keys() ) - m3DMapViewsDom[viewName].setAttribute( QStringLiteral( "isOpen" ), 0 ); - for ( QString viewName : m3DMapViewsDom.keys() ) + for ( Qgs3DMapCanvasDockWidget *widget : findChildren< Qgs3DMapCanvasDockWidget * >() ) { - if ( !m3DMapViewsWidgets.contains( viewName ) ) - continue; - Qgs3DMapCanvasDockWidget *w = m3DMapViewsWidgets[ viewName ]; + QString viewName = widget->mapCanvas3D()->objectName(); QDomElement elem3DMap = doc.createElement( QStringLiteral( "view" ) ); elem3DMap.setAttribute( QStringLiteral( "isOpen" ), 1 ); - write3DMapViewSettings( w, doc, elem3DMap ); - m3DMapViewsDom[ w->mapCanvas3D()->objectName() ] = elem3DMap; + write3DMapViewSettings( widget, doc, elem3DMap ); + QgsProject::instance()->views3DManager()->register3DViewSettings( viewName, elem3DMap ); } - for ( QString viewName : m3DMapViewsDom.keys() ) - { - QDomElement dom = m3DMapViewsDom[viewName]; - elem3DMaps.appendChild( m3DMapViewsDom[viewName] ); - } - qgisNode.appendChild( elem3DMaps ); +// QDomElement elem3DMaps = QgsProject::instance()->views3DManager()->writeXml( doc ); +// qgisNode.appendChild( elem3DMaps ); #endif projectChanged( doc ); } @@ -16877,25 +16871,20 @@ void QgisApp::readProject( const QDomDocument &doc ) } #ifdef HAVE_3D - QgsReadWriteContext readWriteContext; - readWriteContext.setPathResolver( QgsProject::instance()->pathResolver() ); - QDomElement elem3DMaps = doc.documentElement().firstChildElement( QStringLiteral( "mapViewDocks3D" ) ); - if ( !elem3DMaps.isNull() ) + // Open 3D Views that were already open + for ( QDomElement viewConfig : QgsProject::instance()->views3DManager()->get3DViews() ) { - QDomElement elem3DMap = elem3DMaps.firstChildElement( QStringLiteral( "view" ) ); - while ( !elem3DMap.isNull() ) + QString viewName = viewConfig.attribute( QStringLiteral( "name" ) ); + bool isOpen = viewConfig.attribute( QStringLiteral( "isOpen" ), QStringLiteral( "1" ) ).toInt() == 1; + if ( !isOpen ) + continue; + Qgs3DMapCanvasDockWidget *mapCanvasDock3D = createNew3DMapCanvasDock( viewName ); + read3DMapViewSettings( mapCanvasDock3D, viewConfig ); + + connect( mapCanvasDock3D, &Qgs3DMapCanvasDockWidget::closed, [ &, viewName]() { - QString mapName = elem3DMap.attribute( QStringLiteral( "name" ) ); - m3DMapViewsDom.insert( mapName, elem3DMap ); - - if ( elem3DMap.attribute( QStringLiteral( "isOpen" ), QStringLiteral( "1" ) ).toInt() == 1 ) - { - Qgs3DMapCanvasDockWidget *mapCanvasDock3D = createNew3DMapCanvasDock( mapName ); - read3DMapViewSettings( mapCanvasDock3D, elem3DMap ); - } - - elem3DMap = elem3DMap.nextSiblingElement( QStringLiteral( "view" ) ); - } + QgsProject::instance()->views3DManager()->viewClosed( viewName ); + } ); } #endif @@ -17618,7 +17607,6 @@ QgsFeature QgisApp::duplicateFeatureDigitized( QgsMapLayer *mlayer, const QgsFea return QgsFeature(); } - void QgisApp::populateProjectStorageMenu( QMenu *menu, const bool saving ) { menu->clear(); diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index e1ac5e71925..50dd888b150 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -430,6 +430,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow /** * Opens a 3D view canvas for a 3D map view called \a name. + * If the 3D view named \a name was not already created in the project, nullptr will be returned */ Qgs3DMapCanvasDockWidget *open3DMapView( const QString &name ); @@ -2735,10 +2736,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow QMap< QString, QToolButton * > mAnnotationItemGroupToolButtons; QAction *mAnnotationsItemInsertBefore = nullptr; // Used to insert annotation items at the appropriate location in the annotations toolbar -#ifdef HAVE_3D - QMap m3DMapViewsDom; - QMap m3DMapViewsWidgets; -#endif class QgsCanvasRefreshBlocker { diff --git a/src/app/qgsappwindowmanager.cpp b/src/app/qgsappwindowmanager.cpp index e25b7534d7c..d77ec41794b 100644 --- a/src/app/qgsappwindowmanager.cpp +++ b/src/app/qgsappwindowmanager.cpp @@ -21,7 +21,7 @@ #include "qgsrasterlayer.h" #ifdef HAVE_3D -#include "qgs3dviewsmanager.h" +#include "qgs3dviewsmanagerdialog.h" #endif QgsAppWindowManager::~QgsAppWindowManager() @@ -71,7 +71,7 @@ QWidget *QgsAppWindowManager::openApplicationDialog( QgsAppWindowManager::Applic #ifdef HAVE_3D if ( !m3DMapViewsManagerDialog ) { - m3DMapViewsManagerDialog = new Qgs3DViewsManager( QgisApp::instance(), Qt::Window ); + m3DMapViewsManagerDialog = new Qgs3DViewsManagerDialog( QgisApp::instance(), Qt::Window ); m3DMapViewsManagerDialog->setAttribute( Qt::WA_DeleteOnClose ); } m3DMapViewsManagerDialog->show(); diff --git a/src/app/qgsappwindowmanager.h b/src/app/qgsappwindowmanager.h index 5de513a65cb..dedd725be2a 100644 --- a/src/app/qgsappwindowmanager.h +++ b/src/app/qgsappwindowmanager.h @@ -22,7 +22,7 @@ class QgsStyleManagerDialog; class QgsLayoutManagerDialog; -class Qgs3DViewsManager; +class Qgs3DViewsManagerDialog; /** * \ingroup gui @@ -57,7 +57,7 @@ class QgsAppWindowManager : public QgsWindowManagerInterface private: QPointer< QgsStyleManagerDialog > mStyleManagerDialog; QPointer< QgsLayoutManagerDialog > mLayoutManagerDialog; - QPointer< Qgs3DViewsManager > m3DMapViewsManagerDialog; + QPointer< Qgs3DViewsManagerDialog > m3DMapViewsManagerDialog; }; diff --git a/src/core/3d/qgs3dviewsmanager.cpp b/src/core/3d/qgs3dviewsmanager.cpp new file mode 100644 index 00000000000..a719895978b --- /dev/null +++ b/src/core/3d/qgs3dviewsmanager.cpp @@ -0,0 +1,107 @@ +/*************************************************************************** + qgs3dviewsmanager.cpp + ------------------ + Date : December 2021 + Copyright : (C) 2021 Belgacem Nedjima + Email : gb underscore nedjima at esi dot dz + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgs3dviewsmanager.h" +#include "qgsproject.h" +#include "qgsstyleentityvisitor.h" + +Qgs3DViewsManager::Qgs3DViewsManager( QgsProject *project ) + : QObject( project ) +{ + +} + +bool Qgs3DViewsManager::readXml( const QDomElement &element, const QDomDocument &doc ) +{ + clear(); + + QgsReadWriteContext readWriteContext; + readWriteContext.setPathResolver( QgsProject::instance()->pathResolver() ); + QDomElement elem3DMaps = element.firstChildElement( QStringLiteral( "mapViewDocks3D" ) ); + if ( !elem3DMaps.isNull() ) + { + QDomElement elem3DMap = elem3DMaps.firstChildElement( QStringLiteral( "view" ) ); + while ( !elem3DMap.isNull() ) + { + QString mapName = elem3DMap.attribute( QStringLiteral( "name" ) ); + m3DMapViewsDom.insert( mapName, elem3DMap ); + + elem3DMap = elem3DMap.nextSiblingElement( QStringLiteral( "view" ) ); + } + } + + return true; +} + +QDomElement Qgs3DViewsManager::writeXml( QDomDocument &doc ) const +{ + QDomElement dom = doc.createElement( "mapViewDocks3D" ); + for ( QDomElement d : m3DMapViewsDom.values() ) + dom.appendChild( d ); + return dom; +} + +void Qgs3DViewsManager::clear() +{ + m3DMapViewsDom.clear(); + emit viewsListChanged(); +} + +QDomElement Qgs3DViewsManager::get3DViewSettings( const QString &name ) +{ + return m3DMapViewsDom.value( name, QDomElement() ); +} + +QList Qgs3DViewsManager::get3DViews() +{ + return m3DMapViewsDom.values(); +} + +void Qgs3DViewsManager::register3DViewSettings( const QString &name, const QDomElement &dom ) +{ + m3DMapViewsDom.insert( name, dom ); + emit viewsListChanged(); +} + +QStringList Qgs3DViewsManager::get3DViewsNames() +{ + return m3DMapViewsDom.keys(); +} + +void Qgs3DViewsManager::remove3DView( const QString &name ) +{ + m3DMapViewsDom.remove( name ); + emit viewsListChanged(); +} + +void Qgs3DViewsManager::rename3DView( const QString &oldTitle, const QString &newTitle ) +{ + QDomElement elem = m3DMapViewsDom.value( oldTitle ); + m3DMapViewsDom.remove( oldTitle ); + m3DMapViewsDom[ newTitle ] = elem; + emit viewsListChanged(); +} + +void Qgs3DViewsManager::viewClosed( const QString &name ) +{ + if ( m3DMapViewsDom.contains( name ) ) + m3DMapViewsDom[ name ].setAttribute( "isOpen", 0 ); +} + +void Qgs3DViewsManager::viewOpened( const QString &name ) +{ + if ( m3DMapViewsDom.contains( name ) ) + m3DMapViewsDom[ name ].setAttribute( "isOpen", 1 ); +} diff --git a/src/core/3d/qgs3dviewsmanager.h b/src/core/3d/qgs3dviewsmanager.h new file mode 100644 index 00000000000..6b6c1f5b53a --- /dev/null +++ b/src/core/3d/qgs3dviewsmanager.h @@ -0,0 +1,80 @@ +/*************************************************************************** + qgs3dviewsmanager.h + ------------------ + Date : December 2021 + Copyright : (C) 2021 Belgacem Nedjima + Email : gb underscore nedjima at esi dot dz + *************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGS3DVIEWSMANAGER_H +#define QGS3DVIEWSMANAGER_H + +#include "qgis_core.h" +#include "qgis_sip.h" +#include +#include +#include +#include + +class QgsProject; + +/** + * \ingroup core + * \class Qgs3DViewsManager + * + * \brief Manages storage of a set of 3D views. + * + * QgsLayoutManager handles the storage, serializing and deserializing + * of 3D views. Usually this class is not constructed directly, but + * rather accessed through a QgsProject via QgsProject::viewsManager3D(). + * + * Qgs3DViewsManager retains ownership of all the 3d views contained + * in the manager. + * \since QGIS 3.24 + */ +class CORE_EXPORT Qgs3DViewsManager : public QObject +{ + Q_OBJECT + + public: + + /** + * Constructor for Qgs3DViewsManager. The project will become the parent object for this + * manager. + */ + explicit Qgs3DViewsManager( QgsProject *project ); + + bool readXml( const QDomElement &element, const QDomDocument &doc ); + + QDomElement writeXml( QDomDocument &doc ) const; + + void clear(); + + QDomElement get3DViewSettings( const QString &name ); + void register3DViewSettings( const QString &name, const QDomElement &dom ); + + QStringList get3DViewsNames(); + QList get3DViews(); + + void remove3DView( const QString &name ); + void rename3DView( const QString &oldTitle, const QString &newTitle ); + + void viewOpened( const QString &name ); + void viewClosed( const QString &name ); + + signals: + void viewsListChanged(); + + private: + QMap m3DMapViewsDom; +}; + + +#endif // QGSLAYOUTMANAGER_H diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1853cad1aa4..863a9525307 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -779,6 +779,7 @@ set(QGIS_CORE_SRCS 3d/qgs3dsymbolregistry.cpp 3d/qgsabstract3dsymbol.cpp 3d/qgsabstract3drenderer.cpp + 3d/qgs3dviewsmanager.cpp fieldformatter/qgscheckboxfieldformatter.cpp fieldformatter/qgsrangefieldformatter.cpp @@ -1165,6 +1166,7 @@ set(QGIS_CORE_HDRS 3d/qgs3dsymbolregistry.h 3d/qgsabstract3dsymbol.h 3d/qgsabstract3drenderer.h + 3d/qgs3dviewsmanager.h annotations/qgsannotation.h annotations/qgsannotationitem.h diff --git a/src/core/project/qgsproject.cpp b/src/core/project/qgsproject.cpp index ea218d72c04..628c0d71ed9 100644 --- a/src/core/project/qgsproject.cpp +++ b/src/core/project/qgsproject.cpp @@ -66,7 +66,9 @@ #include "qgspointcloudlayer.h" #include "qgsattributeeditorcontainer.h" #include "qgsgrouplayer.h" - +#ifdef HAVE_3D +#include "qgs3dviewsmanager.h" +#endif #include #include @@ -370,6 +372,7 @@ QgsProject::QgsProject( QObject *parent ) , mRelationManager( new QgsRelationManager( this ) ) , mAnnotationManager( new QgsAnnotationManager( this ) ) , mLayoutManager( new QgsLayoutManager( this ) ) + , m3DViewsManager( new Qgs3DViewsManager( this ) ) , mBookmarkManager( QgsBookmarkManager::createProjectBasedManager( this ) ) , mViewSettings( new QgsProjectViewSettings( this ) ) , mTimeSettings( new QgsProjectTimeSettings( this ) ) @@ -840,6 +843,7 @@ void QgsProject::clear() mRelationManager->clear(); mAnnotationManager->clear(); mLayoutManager->clear(); + m3DViewsManager->clear(); mBookmarkManager->clear(); mViewSettings->reset(); mTimeSettings->reset(); @@ -1719,6 +1723,13 @@ bool QgsProject::readProjectFile( const QString &filename, QgsProject::ReadFlags profile.switchTask( tr( "Loading layouts" ) ); mLayoutManager->readXml( doc->documentElement(), *doc ); } + + if ( !( flags & QgsProject::ReadFlag::FlagDontLoad3DViews ) ) + { + profile.switchTask( tr( "Loading 3D Views" ) ); + m3DViewsManager->readXml( doc->documentElement(), *doc ); + } + profile.switchTask( tr( "Loading bookmarks" ) ); mBookmarkManager->readXml( doc->documentElement(), *doc ); @@ -2444,6 +2455,9 @@ bool QgsProject::writeProjectFile( const QString &filename ) const QDomElement layoutElem = mLayoutManager->writeXml( *doc ); qgisNode.appendChild( layoutElem ); + const QDomElement views3DElem = m3DViewsManager->writeXml( *doc ); + qgisNode.appendChild( views3DElem ); + const QDomElement bookmarkElem = mBookmarkManager->writeXml( *doc ); qgisNode.appendChild( bookmarkElem ); @@ -3160,6 +3174,16 @@ QgsLayoutManager *QgsProject::layoutManager() return mLayoutManager.get(); } +const Qgs3DViewsManager *QgsProject::views3DManager() const +{ + return m3DViewsManager.get(); +} + +Qgs3DViewsManager *QgsProject::views3DManager() +{ + return m3DViewsManager.get(); +} + const QgsBookmarkManager *QgsProject::bookmarkManager() const { return mBookmarkManager; diff --git a/src/core/project/qgsproject.h b/src/core/project/qgsproject.h index 0271069fd7b..c99d3d3ea31 100644 --- a/src/core/project/qgsproject.h +++ b/src/core/project/qgsproject.h @@ -82,7 +82,7 @@ class QgsProjectTimeSettings; class QgsAnnotationLayer; class QgsAttributeEditorContainer; class QgsPropertyCollection; - +class Qgs3DViewsManager; /** * \ingroup core @@ -128,6 +128,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera FlagDontLoadLayouts = 1 << 1, //!< Don't load print layouts. Improves project read time if layouts are not required, and allows projects to be safely read in background threads (since print layouts are not thread safe). FlagTrustLayerMetadata = 1 << 2, //!< Trust layer metadata. Improves project read time. Do not use it if layers' extent is not fixed during the project's use by QGIS and QGIS Server. FlagDontStoreOriginalStyles = 1 << 3, //!< Skip the initial XML style storage for layers. Useful for minimising project load times in non-interactive contexts. + FlagDontLoad3DViews = 1 << 4, //!< }; Q_DECLARE_FLAGS( ReadFlags, ReadFlag ) @@ -755,6 +756,21 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera */ QgsLayoutManager *layoutManager(); + /** + * Returns the project's 3D views manager, which manages 3D views + * in the project. + * \note not available in Python bindings + * \since QGIS 3.24 + */ + const Qgs3DViewsManager *views3DManager() const SIP_SKIP; + + /** + * Returns the project's 3D views manager, which manages 3D views + * in the project. + * \since QGIS 3.24 + */ + Qgs3DViewsManager *views3DManager(); + /** * Returns the project's bookmark manager, which manages bookmarks within * the project. @@ -2042,6 +2058,7 @@ class CORE_EXPORT QgsProject : public QObject, public QgsExpressionContextGenera std::unique_ptr mAnnotationManager; std::unique_ptr mLayoutManager; + std::unique_ptr m3DViewsManager; QgsBookmarkManager *mBookmarkManager = nullptr; diff --git a/src/ui/3d/qgs3dviewsmanager.ui b/src/ui/3d/qgs3dviewsmanagerdialog.ui similarity index 96% rename from src/ui/3d/qgs3dviewsmanager.ui rename to src/ui/3d/qgs3dviewsmanagerdialog.ui index 170457544e1..9163a12f697 100644 --- a/src/ui/3d/qgs3dviewsmanager.ui +++ b/src/ui/3d/qgs3dviewsmanagerdialog.ui @@ -1,7 +1,7 @@ - Qgs3DViewsManager - + Qgs3DViewsManagerDialog + 0