From acf1ed3bcb466ddc9bb7bb0404fb23ccab163673 Mon Sep 17 00:00:00 2001 From: Martyn Gigg <martyn.gigg@gmail.com> Date: Thu, 2 May 2019 08:14:37 +0100 Subject: [PATCH] Ask InterfaceManager for known C++ interfaces in workbench Populates the Interfaces menu if any exist. --- MantidPlot/src/ApplicationWindow.cpp | 3 +- .../workbench/workbench/app/mainwindow.py | 78 +++++++++++++------ qt/python/mantidqt/_common.sip | 26 +++++-- qt/python/mantidqt/usersubwindowfactory.py | 15 ++++ .../Common/UserSubWindowFactory.h | 47 ++++++++++- qt/widgets/common/src/InterfaceManager.cpp | 2 +- .../common/src/UserSubWindowFactory.cpp | 47 +---------- 7 files changed, 139 insertions(+), 79 deletions(-) create mode 100644 qt/python/mantidqt/usersubwindowfactory.py diff --git a/MantidPlot/src/ApplicationWindow.cpp b/MantidPlot/src/ApplicationWindow.cpp index 28e05f98eb2..706d97bae07 100644 --- a/MantidPlot/src/ApplicationWindow.cpp +++ b/MantidPlot/src/ApplicationWindow.cpp @@ -508,8 +508,7 @@ void ApplicationWindow::init(bool factorySettings, const QStringList &args) { qMakePair(userSubWindowName, userSubWindowName)); const QSet<QString> categories = - UserSubWindowFactory::Instance().getInterfaceCategories( - userSubWindowName); + UserSubWindowFactory::Instance().categories(userSubWindowName); m_interfaceCategories[userSubWindowName] = categories; m_allCategories += categories; diff --git a/qt/applications/workbench/workbench/app/mainwindow.py b/qt/applications/workbench/workbench/app/mainwindow.py index 7c7aedc2e35..abf4d98d0b6 100644 --- a/qt/applications/workbench/workbench/app/mainwindow.py +++ b/qt/applications/workbench/workbench/app/mainwindow.py @@ -52,6 +52,8 @@ from mantidqt.widgets.codeeditor.execution import PythonCodeExecution # noqa from mantidqt.utils.qt import (add_actions, create_action, plugins, widget_updates_disabled) # noqa from mantidqt.project.project import Project # noqa +from mantidqt.interfacemanager import InterfaceManager # noqa +from mantidqt.usersubwindowfactory import UserSubWindowFactory # noqa # Pre-application setup plugins.setup_library_paths() @@ -175,8 +177,9 @@ class MainWindow(QMainWindow): self.project = None self.project_recovery = None - # Interface Runner - self.executioner = None + # Interfaces + self.interface_manager = None + self.interface_executor = None def setup(self): # menus must be done first so they can be filled by the @@ -226,6 +229,9 @@ class MainWindow(QMainWindow): self.project_recovery = ProjectRecovery(globalfiguremanager=GlobalFigureManager, multifileinterpreter=self.editor.editors, main_window=self) + + self.interface_executor = PythonCodeExecution() + self.interface_executor.sig_exec_error.connect(lambda errobj: logger.warning(str(errobj))) self.interface_manager = InterfaceManager() # uses default configuration as necessary @@ -234,13 +240,12 @@ class MainWindow(QMainWindow): self.setup_layout() self.create_actions() - self.populate_menus() def post_mantid_init(self): """Run any setup that requires mantid to have been initialized """ - self.populate_interfaces_menu() + self.populate_menus() self.algorithm_selector.refresh() # turn on algorithm factory notifications @@ -336,18 +341,41 @@ class MainWindow(QMainWindow): add_actions(self.file_menu, self.file_menu_actions) add_actions(self.view_menu, self.view_menu_actions) add_actions(self.help_menu, self.help_menu_actions) + self.populate_interfaces_menu() - def launch_custom_gui(self, filename): - if self.executioner is None: - self.executioner = PythonCodeExecution() - self.executioner.sig_exec_error.connect(lambda errobj: logger.warning(str(errobj))) - + def launch_custom_python_gui(self, filename): self.executioner.execute(open(filename).read(), filename) + def launch_custom_cpp_gui(self, interface_name): + interface = self.interface_manager.createSubWindow(interface_name) + interface.setAttribute(Qt.WA_DeleteOnClose, True) + interface.show() + def populate_interfaces_menu(self): + """Populate then Interfaces menu with all Python and C++ interfaces""" interface_dir = ConfigService['mantidqt.python_interfaces_directory'] - items = ConfigService['mantidqt.python_interfaces'].split() + interfaces = self._discover_python_interfaces(interface_dir) + interfaces.update(self._discover_cpp_interfaces()) + keys = list(interfaces.keys()) + keys.sort() + for key in keys: + submenu = self.interfaces_menu.addMenu(key) + names = interfaces[key] + names.sort() + for name in names: + if '.py' in name: + action = submenu.addAction(name.replace('.py', '').replace('_', ' ')) + script = os.path.join(interface_dir, name) + action.triggered.connect(lambda checked_py, script=script: self.launch_custom_python_gui(script)) + else: + action = submenu.addAction(name) + action.triggered.connect(lambda checked_cpp, name=name: + self.launch_custom_cpp_gui(name)) + + def _discover_python_interfaces(self, interface_dir): + """Return a dictionary mapping a category to a set of named Python interfaces""" + items = ConfigService['mantidqt.python_interfaces'].split() # list of custom interfaces that are not qt4/qt5 compatible GUI_BLACKLIST = ['ISIS_Reflectometry_Old.py', 'Frequency_Domain_Analysis_Old.py', @@ -364,21 +392,23 @@ class MainWindow(QMainWindow): if scriptname in GUI_BLACKLIST: logger.information('Not adding gui "{}"'.format(scriptname)) continue - temp = interfaces.get(key, []) - temp.append(scriptname) - interfaces[key] = temp + interfaces.setdefault(key, []).append(scriptname) - # add the interfaces to the menu - keys = list(interfaces.keys()) - keys.sort() - for key in keys: - submenu = self.interfaces_menu.addMenu(key) - names = interfaces[key] - names.sort() - for name in names: - action = submenu.addAction(name.replace('.py', '').replace('_', ' ')) - script = os.path.join(interface_dir, name) - action.triggered.connect(lambda checked, script=script: self.launch_custom_gui(script)) + return interfaces + + def _discover_cpp_interfaces(self): + """Return a dictionary mapping a category to a set of named C++ interfaces""" + interfaces = {} + cpp_interface_factory = UserSubWindowFactory.Instance() + interface_names = cpp_interface_factory.keys() + for name in interface_names: + categories = cpp_interface_factory.categories(name) + if len(categories) == 0: + categories = ["General"] + for category in categories: + interfaces.setdefault(category, []).append(name) + + return interfaces def add_dockwidget(self, plugin): """Create a dockwidget around a plugin and add the dock to window""" diff --git a/qt/python/mantidqt/_common.sip b/qt/python/mantidqt/_common.sip index dfafd05aa8a..049b1c0327c 100644 --- a/qt/python/mantidqt/_common.sip +++ b/qt/python/mantidqt/_common.sip @@ -231,12 +231,28 @@ class UserSubWindow : QMainWindow { #include "MantidQtWidgets/Common/UserSubWindow.h" using namespace MantidQt::API; %End -public: +private: UserSubWindow(QWidget *parent = nullptr); - void setInterfaceName(const QString &iface_name); - void initializeLayout(); -protected: - virtual void initLayout() = 0; +}; + +class UserSubWindowFactoryImpl /PyName=UserSubWindowFactory/ { +%TypeHeaderCode +#include "MantidQtWidgets/Common/UserSubWindowFactory.h" +%End +public: + static SIP_PYOBJECT Instance() const; + %MethodCode + auto &cppInstance = MantidQt::API::UserSubWindowFactory::Instance(); + return sipConvertFromType(&cppInstance, sipType_UserSubWindowFactoryImpl, nullptr); + %End + UserSubWindow *createUnwrapped(const std::string &name) const; + QSet<QString> categories(const QString &interfaceName) const; + QStringList keys() const; + +private: + UserSubWindowFactoryImpl(); + UserSubWindowFactoryImpl(const UserSubWindowFactoryImpl &); + ~UserSubWindowFactoryImpl(); }; diff --git a/qt/python/mantidqt/usersubwindowfactory.py b/qt/python/mantidqt/usersubwindowfactory.py new file mode 100644 index 00000000000..ae6ac54b8fa --- /dev/null +++ b/qt/python/mantidqt/usersubwindowfactory.py @@ -0,0 +1,15 @@ +# Mantid Repository : https://github.com/mantidproject/mantid +# +# Copyright © 2019 ISIS Rutherford Appleton Laboratory UKRI, +# NScD Oak Ridge National Laboratory, European Spallation Source +# & Institut Laue - Langevin +# SPDX - License - Identifier: GPL - 3.0 + +# This file is part of the mantidqt package +# +# +from __future__ import (absolute_import) + +from mantidqt.utils.qt import import_qt + + +UserSubWindowFactory = import_qt('._common', 'mantidqt', 'UserSubWindowFactory') diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/UserSubWindowFactory.h b/qt/widgets/common/inc/MantidQtWidgets/Common/UserSubWindowFactory.h index 0806051e2be..ef56205dfa1 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/UserSubWindowFactory.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/UserSubWindowFactory.h @@ -45,9 +45,8 @@ public: // Override createUnwrapped to search through the alias list UserSubWindow *createUnwrapped(const std::string &name) const override; - QSet<QString> getInterfaceCategories(const QString &interfaceName) const; - - QStringList getUserSubWindowKeys() const; + QSet<QString> categories(const QString &interfaceName) const; + QStringList keys() const; template <typename TYPE> void subscribe(); @@ -77,9 +76,51 @@ private: QHash<QString, QSet<QString>> m_categoryLookup; }; +template <typename TYPE> void UserSubWindowFactoryImpl::subscribe() { + std::string realName = TYPE::name(); + Mantid::Kernel::DynamicFactory<UserSubWindow>::subscribe<TYPE>(realName); + saveAliasNames<TYPE>(realName); + + // Make a record of each interface's categories. + const QStringList categories = + TYPE::categoryInfo().split(";", QString::SkipEmptyParts); + QSet<QString> result; + foreach (const QString category, categories) { + result.insert(category.trimmed()); + } + m_categoryLookup[QString::fromStdString(realName)] = result; +} + +/** + * Save the alias names of an interface + * @param realName :: The real name of the interface + */ +template <typename TYPE> +void UserSubWindowFactoryImpl::saveAliasNames(const std::string &realName) { + std::set<std::string> aliases = TYPE::aliases(); + for (const auto &alias_std_str : aliases) { + QString alias = QString::fromStdString(alias_std_str); + if (m_aliasLookup.contains(alias)) { + if (m_badAliases.contains(alias)) { + QList<std::string> names = m_badAliases.value(alias); + names.append(realName); + m_badAliases[alias] = names; + } else { + QList<std::string> names; + names.append(m_aliasLookup.value(alias)); + names.append(realName); + m_badAliases.insert(alias, names); + } + continue; + } + m_aliasLookup.insert(alias, realName); + } +} + /// The specific instantiation of the templated type using UserSubWindowFactory = Mantid::Kernel::SingletonHolder<UserSubWindowFactoryImpl>; + } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 1ded3ba974d..494e3cc53bf 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -176,7 +176,7 @@ UserSubWindow *InterfaceManager::createSubWindow(const QString &interface_name, * refer to UserSubWindow classes */ QStringList InterfaceManager::getUserSubWindowKeys() const { - return UserSubWindowFactory::Instance().getUserSubWindowKeys(); + return UserSubWindowFactory::Instance().keys(); } //---------------------------------- diff --git a/qt/widgets/common/src/UserSubWindowFactory.cpp b/qt/widgets/common/src/UserSubWindowFactory.cpp index ee29cd9db8a..da47021dcda 100644 --- a/qt/widgets/common/src/UserSubWindowFactory.cpp +++ b/qt/widgets/common/src/UserSubWindowFactory.cpp @@ -68,8 +68,8 @@ UserSubWindowFactoryImpl::createUnwrapped(const std::string &name) const { *been registered, * else an empty set. */ -QSet<QString> UserSubWindowFactoryImpl::getInterfaceCategories( - const QString &interfaceName) const { +QSet<QString> +UserSubWindowFactoryImpl::categories(const QString &interfaceName) const { if (!m_categoryLookup.contains(interfaceName)) return QSet<QString>(); @@ -114,53 +114,12 @@ UserSubWindowFactoryImpl::createFromAlias(const std::string &name) const { } } -template <typename TYPE> void UserSubWindowFactoryImpl::subscribe() { - std::string realName = TYPE::name(); - Mantid::Kernel::DynamicFactory<UserSubWindow>::subscribe<TYPE>(realName); - saveAliasNames<TYPE>(realName); - - // Make a record of each interface's categories. - const QStringList categories = - TYPE::categoryInfo().split(";", QString::SkipEmptyParts); - QSet<QString> result; - foreach (const QString category, categories) { - result.insert(category.trimmed()); - } - m_categoryLookup[QString::fromStdString(realName)] = result; -} - -/** - * Save the alias names of an interface - * @param realName :: The real name of the interface - */ -template <typename TYPE> -void UserSubWindowFactoryImpl::saveAliasNames(const std::string &realName) { - std::set<std::string> aliases = TYPE::aliases(); - for (const auto &alias_std_str : aliases) { - QString alias = QString::fromStdString(alias_std_str); - if (m_aliasLookup.contains(alias)) { - if (m_badAliases.contains(alias)) { - QList<std::string> names = m_badAliases.value(alias); - names.append(realName); - m_badAliases[alias] = names; - } else { - QList<std::string> names; - names.append(m_aliasLookup.value(alias)); - names.append(realName); - m_badAliases.insert(alias, names); - } - continue; - } - m_aliasLookup.insert(alias, realName); - } -} - /** * The keys associated with UserSubWindow classes * @returns A QStringList containing the keys from the UserSubWindowFactory that * refer to UserSubWindow classes */ -QStringList UserSubWindowFactoryImpl::getUserSubWindowKeys() const { +QStringList UserSubWindowFactoryImpl::keys() const { QStringList key_list; const auto keys = getKeys(); for (const auto &key : keys) { -- GitLab