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.
This commit is contained in:
Nyall Dawson 2024-12-06 10:24:09 +10:00
parent 806ea8b9cf
commit c33b4e67dc
8 changed files with 77 additions and 31 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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)

View File

@ -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; }

View File

@ -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(); }

View File

@ -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;

View File

@ -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.
*/

View File

@ -62,6 +62,11 @@
<addaction name="separator"/>
<addaction name="mActionDwgImport"/>
</widget>
<widget class="QMenu" name="mMenuProjectModels">
<property name="title">
<string>Models</string>
</property>
</widget>
<addaction name="mActionNewProject"/>
<addaction name="mProjectFromTemplateMenu"/>
<addaction name="separator"/>
@ -85,6 +90,8 @@
<addaction name="mActionShowLayoutManager"/>
<addaction name="mLayoutsMenu"/>
<addaction name="separator"/>
<addaction name="mMenuProjectModels"/>
<addaction name="separator"/>
<addaction name="mActionExit"/>
</widget>
<widget class="QMenu" name="mViewMenu">