From c33b4e67dc5cd5bf6583e5a2aadde78a47ffdfb0 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 6 Dec 2024 10:24:09 +1000 Subject: [PATCH] Fix exception when loading processing plugin on Qt 6 builds on KDE Something internal in KDE itself adds child QObjects to menus, so the code which tries to find the last action in the menu fails and returns a QObject instead of a QAction, leading to an exception in the insertAction call. This is all too fragile anyway, so avoid it by: - Just creating the models menu directly in the ui - Exposing this via interface for use in the processing plugin Now there's no risk of this code breaking in future if the Project menu is re-arranged. --- .../gui/auto_generated/qgisinterface.sip.in | 14 ++++++ .../gui/auto_generated/qgisinterface.sip.in | 14 ++++++ python/plugins/processing/ProcessingPlugin.py | 44 ++++++------------- src/app/qgisapp.h | 1 + src/app/qgisappinterface.cpp | 12 +++++ src/app/qgisappinterface.h | 2 + src/gui/qgisinterface.h | 14 ++++++ src/ui/qgisapp.ui | 7 +++ 8 files changed, 77 insertions(+), 31 deletions(-) diff --git a/python/PyQt6/gui/auto_generated/qgisinterface.sip.in b/python/PyQt6/gui/auto_generated/qgisinterface.sip.in index 04d4e289c18..23ba2a17d58 100644 --- a/python/PyQt6/gui/auto_generated/qgisinterface.sip.in +++ b/python/PyQt6/gui/auto_generated/qgisinterface.sip.in @@ -245,6 +245,20 @@ Adds an ``action`` to the QGIS "Export project" menu. .. seealso:: :py:func:`removeProjectImportAction` .. versionadded:: 3.30 +%End + + virtual QMenu *projectModelsMenu() = 0; +%Docstring +Returns a reference to the main window "Projects" - "Models" submenu. + +.. versionadded:: 3.42 +%End + + virtual QMenu *createProjectModelSubMenu( const QString &title ) = 0; +%Docstring +Creates a new project model submenu in the "Projects" - "Models" submenu. + +.. versionadded:: 3.42 %End virtual QMenu *editMenu() = 0; diff --git a/python/gui/auto_generated/qgisinterface.sip.in b/python/gui/auto_generated/qgisinterface.sip.in index 04d4e289c18..23ba2a17d58 100644 --- a/python/gui/auto_generated/qgisinterface.sip.in +++ b/python/gui/auto_generated/qgisinterface.sip.in @@ -245,6 +245,20 @@ Adds an ``action`` to the QGIS "Export project" menu. .. seealso:: :py:func:`removeProjectImportAction` .. versionadded:: 3.30 +%End + + virtual QMenu *projectModelsMenu() = 0; +%Docstring +Returns a reference to the main window "Projects" - "Models" submenu. + +.. versionadded:: 3.42 +%End + + virtual QMenu *createProjectModelSubMenu( const QString &title ) = 0; +%Docstring +Creates a new project model submenu in the "Projects" - "Models" submenu. + +.. versionadded:: 3.42 %End virtual QMenu *editMenu() = 0; diff --git a/python/plugins/processing/ProcessingPlugin.py b/python/plugins/processing/ProcessingPlugin.py index 07a74378508..5ed8a6a05c8 100644 --- a/python/plugins/processing/ProcessingPlugin.py +++ b/python/plugins/processing/ProcessingPlugin.py @@ -380,11 +380,6 @@ class ProcessingPlugin(QObject): ) self.sync_in_place_button_state() - # Sync project models - self.projectModelsMenu = None - self.projectMenuAction = None - self.projectMenuSeparator = None - self.projectProvider = ( QgsApplication.instance().processingRegistry().providerById("project") ) @@ -394,38 +389,32 @@ class ProcessingPlugin(QObject): def updateProjectModelMenu(self): """Add projects models to menu""" - - if self.projectMenuAction is None: - self.projectModelsMenu = QMenu(self.tr("Models")) - self.projectMenuAction = self.iface.projectMenu().insertMenu( - self.iface.projectMenu().children()[-1], self.projectModelsMenu - ) - self.projectMenuAction.setParent(self.projectModelsMenu) - self.iface.projectMenu().insertSeparator(self.projectMenuAction) - - self.projectModelsMenu.clear() + self.iface.projectModelsMenu().clear() for model in self.projectProvider.algorithms(): - modelSubMenu = self.projectModelsMenu.addMenu(model.name()) - modelSubMenu.setParent(self.projectModelsMenu) - action = QAction(self.tr("Execute…"), modelSubMenu) + model_sub_menu = self.iface.createProjectModelSubMenu(model.name()) + + action = QAction(self.tr("Execute…")) + action.setParent(model_sub_menu) action.triggered.connect( partial( self.executeAlgorithm, model.id(), - self.projectModelsMenu, + self.iface.projectModelsMenu(), self.toolbox.in_place_mode, ) ) - modelSubMenu.addAction(action) + model_sub_menu.addAction(action) if model.flags() & QgsProcessingAlgorithm.Flag.FlagSupportsBatch: - action = QAction(self.tr("Execute as Batch Process…"), modelSubMenu) - modelSubMenu.addAction(action) - action.triggered.connect( + action_batch = QAction( + self.tr("Execute as Batch Process…"), model_sub_menu + ) + model_sub_menu.addAction(action_batch) + action_batch.triggered.connect( partial( self.executeAlgorithm, model.id(), - self.projectModelsMenu, + self.iface.projectModelsMenu(), self.toolbox.in_place_mode, True, ) @@ -580,13 +569,6 @@ class ProcessingPlugin(QObject): removeButtons() removeMenus() - if self.projectMenuAction is not None: - self.iface.projectMenu().removeAction(self.projectMenuAction) - self.projectMenuAction = None - if self.projectMenuSeparator is not None: - self.iface.projectMenu().removeAction(self.projectMenuSeparator) - self.projectMenuSeparator = None - QgsGui.historyProviderRegistry().providerById( "processing" ).executePython.disconnect(self._execute_history_commands) diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 06116147f7b..c5bd9ecb5ce 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -665,6 +665,7 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow //! Menus QMenu *projectMenu() { return mProjectMenu; } QMenu *projectImportExportMenu() { return menuImport_Export; } + QMenu *projectModelsMenu() { return mMenuProjectModels; } QMenu *editMenu() { return mEditMenu; } QMenu *viewMenu() { return mViewMenu; } QMenu *layerMenu() { return mLayerMenu; } diff --git a/src/app/qgisappinterface.cpp b/src/app/qgisappinterface.cpp index 5c9fcf46c60..6b8617c50a7 100644 --- a/src/app/qgisappinterface.cpp +++ b/src/app/qgisappinterface.cpp @@ -733,6 +733,18 @@ void QgisAppInterface::removeProjectExportAction( QAction *action ) } } +QMenu *QgisAppInterface::projectModelsMenu() +{ + return qgis->projectModelsMenu(); +} + +QMenu *QgisAppInterface::createProjectModelSubMenu( const QString &title ) +{ + QMenu *modelSubMenu = new QMenu( title, qgis->projectModelsMenu() ); + qgis->projectModelsMenu()->addMenu( modelSubMenu ); + return modelSubMenu; +} + QMenu *QgisAppInterface::editMenu() { return qgis->editMenu(); } QMenu *QgisAppInterface::viewMenu() { return qgis->viewMenu(); } QMenu *QgisAppInterface::layerMenu() { return qgis->layerMenu(); } diff --git a/src/app/qgisappinterface.h b/src/app/qgisappinterface.h index b529179e8eb..ca0adceab7a 100644 --- a/src/app/qgisappinterface.h +++ b/src/app/qgisappinterface.h @@ -172,6 +172,8 @@ class APP_EXPORT QgisAppInterface : public QgisInterface void removeProjectImportAction( QAction *action ) override; void addProjectExportAction( QAction *action ) override; void removeProjectExportAction( QAction *action ) override; + QMenu *projectModelsMenu() override; + QMenu *createProjectModelSubMenu( const QString &title ) override; QMenu *editMenu() override; QMenu *viewMenu() override; QMenu *layerMenu() override; diff --git a/src/gui/qgisinterface.h b/src/gui/qgisinterface.h index 4c454e6c3ba..be661548ab4 100644 --- a/src/gui/qgisinterface.h +++ b/src/gui/qgisinterface.h @@ -281,6 +281,20 @@ class GUI_EXPORT QgisInterface : public QObject */ virtual void removeProjectExportAction( QAction *action ) = 0; + /** + * Returns a reference to the main window "Projects" - "Models" submenu. + * + * \since QGIS 3.42 + */ + virtual QMenu *projectModelsMenu() = 0; + + /** + * Creates a new project model submenu in the "Projects" - "Models" submenu. + * + * \since QGIS 3.42 + */ + virtual QMenu *createProjectModelSubMenu( const QString &title ) = 0; + /** * Returns a reference to the main window "Edit" menu. */ diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui index 7801d10e655..c105f8a4f92 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -62,6 +62,11 @@ + + + Models + + @@ -85,6 +90,8 @@ + +