From 7c77ae98784b8c131077d8edfba29c4896625872 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Thu, 5 Dec 2024 10:25:20 -0500 Subject: [PATCH 01/28] Changes to facilitate new HelpWindow design --- .../widgets/helpwindow/helpwindowmodel.py | 29 +++ .../widgets/helpwindow/helpwindowpresenter.py | 70 +++++ .../widgets/helpwindow/helpwindowview.py | 43 ++++ .../inc/MantidQtWidgets/Common/HelpWindow.h | 33 ++- .../MantidQtWidgets/Common/InterfaceManager.h | 31 ++- qt/widgets/common/src/HelpWindow.cpp | 33 ++- qt/widgets/common/src/InterfaceManager.cpp | 242 +++++------------- 7 files changed, 293 insertions(+), 188 deletions(-) create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py new file mode 100644 index 000000000000..bb0c15c25aa2 --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py @@ -0,0 +1,29 @@ +class HelpModel: + def __init__(self): + self.history = [] # Track visited URLs + self.current_index = -1 # Current position in history + + def add_url(self, url): + """Add a URL to the history, truncating forward history if necessary.""" + if self.current_index < len(self.history) - 1: + self.history = self.history[: self.current_index + 1] + self.history.append(url) + self.current_index += 1 + + def go_back(self): + """Navigate back in the history.""" + if self.current_index > 0: + self.current_index -= 1 + return self.history[self.current_index] + + def go_forward(self): + """Navigate forward in the history.""" + if self.current_index < len(self.history) - 1: + self.current_index += 1 + return self.history[self.current_index] + + def get_current_url(self): + """Get the current URL.""" + if self.current_index >= 0: + return self.history[self.current_index] + return None diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py new file mode 100644 index 000000000000..aca5dd84a5f0 --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py @@ -0,0 +1,70 @@ +from helpwindowmodel import HelpModel +from helpwindowview import HelpView +from qtpy.QtWidgets import QApplication + + +class HelpPresenter: + _instance = None # Singleton instance for integration + + @classmethod + def instance(cls): + """Ensure a single instance of HelpPresenter.""" + if cls._instance is None: + app = QApplication.instance() or QApplication([]) # noqa: F841 + model = HelpModel() + view = HelpView(None) + cls._instance = cls(model, view) + cls._instance.view = view + return cls._instance + + def __init__(self, model, view): + self.model = model + self.view = view + + def handle_url_changed(self, url): + """Handle URL changes in the view.""" + self.model.add_url(url.toString()) + self.update_navigation_buttons() + + def handle_go_back(self): + """Handle the back button click.""" + url = self.model.go_back() + if url: + self.view.set_url(url) + self.update_navigation_buttons() + + def handle_go_forward(self): + """Handle the forward button click.""" + url = self.model.go_forward() + if url: + self.view.set_url(url) + self.update_navigation_buttons() + + def handle_go_home(self): + """Handle the home button click.""" + url = self.model.history[0] if self.model.history else "about:blank" + self.view.set_url(url) + + def show_page(self, url): + """Load a page in the view.""" + self.model.add_url(url) + self.view.set_url(url) + self.update_navigation_buttons() + + def show_algorithm(self, name, version): + """Show an algorithm-specific help page.""" + base_url = "file:///path/to/docs/algorithms/" + algorithm_url = f"{base_url}{name}-v{version}.html" + self.show_page(algorithm_url) + + def show_concept(self, name): + """Show a concept-specific help page.""" + base_url = "file:///path/to/docs/concepts/" + concept_url = f"{base_url}{name}.html" + self.show_page(concept_url) + + def update_navigation_buttons(self): + """Update the state of navigation buttons in the view.""" + can_go_back = self.model.current_index > 0 + can_go_forward = self.model.current_index < len(self.model.history) - 1 + self.view.update_navigation_buttons(can_go_back, can_go_forward) diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py new file mode 100644 index 000000000000..1ba8dfd60a08 --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -0,0 +1,43 @@ +from qtpy.QtCore import QUrl +from qtpy.QtWidgets import QVBoxLayout, QWidget, QPushButton, QHBoxLayout +from qtpy.QtWebEngineWidgets import QWebEngineView + + +class HelpView(QWidget): + def __init__(self, presenter, parent=None): + super().__init__(parent) + self.presenter = presenter + + self.setWindowTitle("Mantid Help Window") + self.setGeometry(100, 100, 1200, 800) + + # Web view setup + self.webview = QWebEngineView() + self.webview.urlChanged.connect(self.presenter.handle_url_changed) + + # Navigation buttons + self.back_button = QPushButton("Back") + self.back_button.clicked.connect(self.presenter.handle_go_back) + self.forward_button = QPushButton("Forward") + self.forward_button.clicked.connect(self.presenter.handle_go_forward) + self.home_button = QPushButton("Home") + self.home_button.clicked.connect(self.presenter.handle_go_home) + + nav_layout = QHBoxLayout() + nav_layout.addWidget(self.back_button) + nav_layout.addWidget(self.forward_button) + nav_layout.addWidget(self.home_button) + + # Layout setup + main_layout = QVBoxLayout(self) + main_layout.addLayout(nav_layout) + main_layout.addWidget(self.webview) + + def set_url(self, url): + """Set the URL in the webview.""" + self.webview.setUrl(QUrl(url)) + + def update_navigation_buttons(self, can_go_back, can_go_forward): + """Enable or disable navigation buttons.""" + self.back_button.setEnabled(can_go_back) + self.forward_button.setEnabled(can_go_forward) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 22904045d8be..8ea40d15160c 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -8,28 +8,57 @@ #include "MantidQtWidgets/Common/DllOption.h" #include +#include #include -// forward declarations +// Forward declarations class QUrl; namespace MantidQt { namespace API { -class EXPORT_OPT_MANTIDQT_COMMON HelpWindow { +/** + * HelpWindow provides a centralized interface for displaying + * help pages, algorithm details, and concepts. It supports both + * the C++ HelpWindow and launching a Python-based HelpWindow. + */ +class EXPORT_OPT_MANTIDQT_COMMON HelpWindow : public QWidget { + Q_OBJECT + public: + explicit HelpWindow(QWidget *parent = nullptr); + + /// Show a page by URL static void showPage(const std::string &url = std::string()); static void showPage(const QString &url); static void showPage(const QUrl &url); + + /// Show algorithm help by name and version static void showAlgorithm(const std::string &name = std::string(), const int version = -1); static void showAlgorithm(const QString &name, const int version = -1); + + /// Show concept help by name static void showConcept(const std::string &name = std::string()); static void showConcept(const QString &name); + + /// Show fit function help static void showFitFunction(const std::string &name = std::string()); + + /// Show custom interface help static void showCustomInterface(const QString &name, const QString &area = QString(), const QString §ion = QString()); static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), const std::string §ion = std::string()); + + /// Launch the Python-based HelpWindow with the current page + void launchPythonHelp(); + + /// Get the current page URL + QString currentPageUrl() const; + +private: + QString currentUrl; ///< Tracks the current URL displayed in the HelpWindow }; + } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index e8c8fe0d3a45..7dd581ee34d9 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -9,8 +9,9 @@ //---------------------------------- // Includes //---------------------------------- +#include + #include "DllOption.h" -// #include "MantidKernel/SingletonHolder.h" #include "MantidKernel/Instantiator.h" #include @@ -47,9 +48,7 @@ class MantidHelpInterface; /** This class is responsible for creating the correct dialog for an algorithm. - If - no specialized version is registered for that algorithm then the default is - created + If no specialized version is registered for that algorithm then the default is created. @author Martyn Gigg, Tessella Support Services plc @date 24/02/2009 @@ -81,32 +80,38 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { */ MantidHelpInterface *createHelpWindow() const; - /// @param url Relative URL of help page to show. + /// Show a help page by URL void showHelpPage(const QString &url = QString()); - /// @param name of algorithm to show help for - /// @param version of algorithm + /// Show algorithm help by name and version void showAlgorithmHelp(const QString &name, const int version = -1); - /// @param name of concept to show help for + /// Show concept help by name void showConceptHelp(const QString &name); - /// @param name of fit function to show help for + /// Show fit function help void showFitFunctionHelp(const QString &name = QString()); /** * @param name of interface to show help for * @param area - folder for documentation in the interfaces directory - * @param section - section in the html document - **/ + * @param section - section in the HTML document + */ void showCustomInterfaceHelp(const QString &name, const QString &area = QString(), const QString §ion = QString()); - /// @param url of web page to open in browser + /// Open a web page by URL void showWebPage(const QString &url); + /// Close the active help window void closeHelpWindow(); + /** + * Launch the Python-based HelpWindow + * @param url :: URL to pass to the Python HelpWindow + */ + void launchPythonHelp(const QString &url); + /** * Registration function for the help window factory. * @param factory the factory instance @@ -121,6 +126,7 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Constructor InterfaceManager(); + /// Destructor virtual ~InterfaceManager(); @@ -130,6 +136,7 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; }; + } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/src/HelpWindow.cpp b/qt/widgets/common/src/HelpWindow.cpp index 1d7063bf257d..37985d9a03f8 100644 --- a/qt/widgets/common/src/HelpWindow.cpp +++ b/qt/widgets/common/src/HelpWindow.cpp @@ -4,6 +4,7 @@ // NScD Oak Ridge National Laboratory, European Spallation Source, // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + + #include "MantidQtWidgets/Common/HelpWindow.h" #include "MantidKernel/ConfigService.h" #include "MantidKernel/Exception.h" @@ -12,9 +13,11 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" +#include #include +#include #include -#include +#include namespace MantidQt::API { namespace { @@ -57,7 +60,6 @@ void HelpWindow::showAlgorithm(const QString &name, const int version) { if (gui) { gui->showAlgorithm(name, version); } else { - // Open online help QString baseUrl = "https://docs.mantidproject.org/algorithms/"; QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; MantidDesktopServices::openUrl(QUrl(url)); @@ -97,7 +99,6 @@ void HelpWindow::showCustomInterface(const QString &name, const QString &area, c if (gui) { gui->showCustomInterface(name, area, section); } else { - // Open online help QString baseUrl = "https://docs.mantidproject.org/interfaces/"; if (!area.toStdString().empty()) { baseUrl += area + "/"; @@ -108,4 +109,30 @@ void HelpWindow::showCustomInterface(const QString &name, const QString &area, c } } +void HelpWindow::launchPythonHelp() { + try { + boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); + boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); + + std::string currentPage = currentUrl.toStdString(); + boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), + mainNamespace); + } catch (const boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Failed to launch Python HelpWindow."); + } +} + +HelpWindow::HelpWindow(QWidget *parent) : QWidget(parent), currentUrl("about:blank") { + auto *layout = new QVBoxLayout(this); + + QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); + connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); + layout->addWidget(pythonHelpButton); +} + +QString HelpWindow::currentPageUrl() const { + return this->currentUrl; // Provide the current URL +} + } // namespace MantidQt::API diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index d8e5d08899c5..26c65a6c958b 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -24,6 +24,7 @@ #include #include +#include using namespace MantidQt::API; using Mantid::Kernel::AbstractInstantiator; @@ -41,170 +42,96 @@ bool offlineHelpMsgDisplayed = false; } // namespace -// initialise HelpWindow factory +// Initialise HelpWindow factory Mantid::Kernel::AbstractInstantiator *InterfaceManager::m_helpViewer = nullptr; //---------------------------------- // Public member functions //---------------------------------- + /** - * Return a specialized dialog for the given algorithm. If none exists then the - * default is returned - * @param alg :: A pointer to the algorithm - * @param parent :: An optional parent widget - * @param forScript :: A boolean indicating if this dialog is to be use for from - * a script or not. If true disables the autoexecution of the dialog - * @param presetValues :: A hash of property names to preset values for the - * dialog - * @param optionalMsg :: An optional message string to be placed at the top of - * the dialog - * @param enabled :: These properties will be left enabled - * @param disabled :: These properties will be left disabled - * @returns An AlgorithmDialog object + * Show a help page using the default or Python-based HelpWindow + * @param url :: URL of the page to be displayed */ -AlgorithmDialog *InterfaceManager::createDialog(const std::shared_ptr &alg, QWidget *parent, - bool forScript, const QHash &presetValues, - const QString &optionalMsg, const QStringList &enabled, - const QStringList &disabled) { - AlgorithmDialog *dlg = nullptr; - if (AlgorithmDialogFactory::Instance().exists(alg->name() + "Dialog")) { - g_log.debug() << "Creating a specialised dialog for " << alg->name() << '\n'; - dlg = AlgorithmDialogFactory::Instance().createUnwrapped(alg->name() + "Dialog"); +void InterfaceManager::showHelpPage(const QString &url) { + auto window = createHelpWindow(); + if (window) { + window->showPage(url); } else { - dlg = new GenericDialog; - g_log.debug() << "No specialised dialog exists for the " << alg->name() - << " algorithm: a generic one has been created\n"; + launchPythonHelp(url); } - - // The parent so that the dialog appears on top of it - dlg->setParent(parent); - dlg->setAttribute(Qt::WA_DeleteOnClose, true); - - // Set the QDialog window flags to ensure the dialog ends up on top - Qt::WindowFlags flags = Qt::WindowFlags(); -#ifdef Q_OS_MAC - // Work around to ensure that floating windows remain on top of the main - // application window, but below other applications on Mac - // Note: Qt::Tool cannot have both a max and min button on OSX - flags |= Qt::Tool; - flags |= Qt::CustomizeWindowHint; - flags |= Qt::WindowMinimizeButtonHint; - flags |= Qt::WindowCloseButtonHint; -#else - flags |= Qt::Dialog; - flags |= Qt::WindowCloseButtonHint; -#endif - dlg->setWindowFlags(flags); - - // Set the content - dlg->setAlgorithm(alg); - dlg->setPresetValues(presetValues); - dlg->isForScript(forScript); - dlg->setOptionalMessage(optionalMsg); - dlg->addEnabledAndDisableLists(enabled, disabled); - - // Setup the layout - dlg->initializeLayout(); - - if (forScript) - dlg->executeOnAccept(false); // override default - return dlg; -} - -/** - * @param algorithmName :: Name of AlgorithmDialog - * @param version :: Version number - * @param parent :: An optional parent widget - * @param forScript :: A boolean indicating if this dialog is to be use for from - * a script or not - * @param presetValues :: A hash of property names to preset values for the - * dialog - * @param optionalMsg :: An optional message string to be placed at the top of - * the dialog - * @param enabled :: These properties will be left enabled - * @param disabled :: These properties will be left disabled - */ -AlgorithmDialog *InterfaceManager::createDialogFromName(const QString &algorithmName, const int version, - QWidget *parent, bool forScript, - const QHash &presetValues, - const QString &optionalMsg, const QStringList &enabled, - const QStringList &disabled) { - // Create the algorithm. This should throw if the algorithm can't be found. - auto alg = Mantid::API::AlgorithmManager::Instance().create(algorithmName.toStdString(), version); - - // Forward call. - return createDialog(alg, parent, forScript, presetValues, optionalMsg, enabled, disabled); } /** - * Create a new instance of the correct type of UserSubWindow - * @param interface_name :: The registered name of the interface - * @param parent :: The parent widget - * @param isWindow :: Should the widget be an independent window + * Launch the Python-based HelpWindow + * @param url :: URL to pass to the Python HelpWindow */ -UserSubWindow *InterfaceManager::createSubWindow(const QString &interface_name, QWidget *parent, bool isWindow) { - UserSubWindow *user_win = nullptr; - std::string iname = interface_name.toStdString(); +void InterfaceManager::launchPythonHelp(const QString &url) { try { - user_win = UserSubWindowFactory::Instance().createUnwrapped(iname); - } catch (Mantid::Kernel::Exception::NotFoundError &) { - user_win = nullptr; - } - if (user_win) { - g_log.debug() << "Created a specialised interface for " << iname << '\n'; - - // set the parent. Note - setParent without flags parameter resets the flags - // ie window becomes a child widget - if (isWindow) { - user_win->setParent(parent, user_win->windowFlags()); - } else { - user_win->setParent(parent); - } + boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); + boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); - user_win->setInterfaceName(interface_name); - user_win->initializeLayout(); + std::string currentPage = url.toStdString(); + boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), + mainNamespace); - notifyExistingInterfaces(user_win); + g_log.information("Launched Python-based HelpWindow."); + } catch (const boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Failed to launch Python HelpWindow."); + } +} +void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { + auto window = createHelpWindow(); + if (window) { + window->showAlgorithm(name, version); } else { - g_log.error() << "Error creating interface " << iname << "\n"; + QString url = QString("file:///path/to/docs/algorithms/%1-v%2.html").arg(name).arg(version); + launchPythonHelp(url); } - return user_win; } -/** - * Notifies the existing interfaces that a new interface has been created, and - * then notifies the new interface about the other interfaces which already - * exist. This can be used to connect signals between interfaces (override - * otherUserSubWindowCreated in the interface class). - * - * @param newWindow :: The interface just created - */ -void InterfaceManager::notifyExistingInterfaces(UserSubWindow *newWindow) { - auto &existingWindows = existingInterfaces(); - - for (auto &window : existingWindows) - window->otherUserSubWindowCreated(newWindow); - - newWindow->otherUserSubWindowCreated(existingWindows); +void InterfaceManager::showConceptHelp(const QString &name) { + auto window = createHelpWindow(); + if (window) { + window->showConcept(name); + } else { + QString url = QString("file:///path/to/docs/concepts/%1.html").arg(name); + launchPythonHelp(url); + } +} - existingWindows.append(newWindow); +void InterfaceManager::showFitFunctionHelp(const QString &name) { + auto window = createHelpWindow(); + if (window) { + window->showFitFunction(name); + } else { + g_log.error("Fit function help is not implemented in the Python-based HelpWindow."); + } } -QList> &InterfaceManager::existingInterfaces() { - static QList> existingSubWindows; - existingSubWindows.erase(std::remove_if(existingSubWindows.begin(), existingSubWindows.end(), - [](QPointer &window) { return window.isNull(); }), - existingSubWindows.end()); - return existingSubWindows; +void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { + auto window = createHelpWindow(); + if (window) { + window->showCustomInterface(name, area, section); + } else { + QString url = QString("file:///path/to/docs/interfaces/%1/%2.html").arg(area).arg(name); + launchPythonHelp(url); + } } +void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } + /** - * The keys associated with UserSubWindow classes - * @returns A QStringList containing the keys from the InterfaceFactory that - * refer to UserSubWindow classes + * Closes the active HelpWindow, if any. */ -QStringList InterfaceManager::getUserSubWindowKeys() const { return UserSubWindowFactory::Instance().keys(); } +void InterfaceManager::closeHelpWindow() { + if (MantidHelpWindow::helpWindowExists()) { + auto window = createHelpWindow(); + window->shutdown(); + } +} //---------------------------------- // Private member functions @@ -218,10 +145,17 @@ InterfaceManager::InterfaceManager() { /// Destructor InterfaceManager::~InterfaceManager() = default; +/** + * Register the HelpWindow factory + * @param factory :: The factory instance + */ void InterfaceManager::registerHelpWindowFactory(Mantid::Kernel::AbstractInstantiator *factory) { m_helpViewer = factory; } +/** + * Create an instance of the appropriate HelpWindow + */ MantidHelpInterface *InterfaceManager::createHelpWindow() const { if (m_helpViewer == nullptr) { if (!offlineHelpMsgDisplayed) { @@ -230,44 +164,10 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } return nullptr; } else { - MantidHelpInterface *interface = this->m_helpViewer->createUnwrappedInstance(); + auto *interface = m_helpViewer->createUnwrappedInstance(); if (!interface) { g_log.error("Error creating help window"); } return interface; } } - -void InterfaceManager::showHelpPage(const QString &url) { - auto window = createHelpWindow(); - window->showPage(url); -} - -void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { - auto window = createHelpWindow(); - window->showAlgorithm(name, version); -} - -void InterfaceManager::showConceptHelp(const QString &name) { - auto window = createHelpWindow(); - window->showConcept(name); -} - -void InterfaceManager::showFitFunctionHelp(const QString &name) { - auto window = createHelpWindow(); - window->showFitFunction(name); -} - -void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { - auto window = createHelpWindow(); - window->showCustomInterface(name, area, section); -} - -void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } - -void InterfaceManager::closeHelpWindow() { - if (MantidHelpWindow::helpWindowExists()) { - auto window = createHelpWindow(); - window->shutdown(); - } -} From a7644458a86387602691336e7af4c396520ebad8 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Mon, 9 Dec 2024 15:16:49 -0500 Subject: [PATCH 02/28] Some updates to make branch current, tests in next --- .../widgets/helpwindow/helpwindowmodel.py | 32 +-- .../widgets/helpwindow/helpwindowpresenter.py | 80 +----- .../widgets/helpwindow/helpwindowview.py | 65 ++--- qt/widgets/common/CMakeLists.txt | 4 + .../inc/MantidQtWidgets/Common/HelpWindow.h | 49 ++-- qt/widgets/common/src/HelpWindow.cpp | 268 +++++++++++------- .../common/src/SelectFunctionDialog.cpp | 2 +- 7 files changed, 244 insertions(+), 256 deletions(-) diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py index bb0c15c25aa2..15ef280736ac 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py @@ -1,29 +1,7 @@ -class HelpModel: +class HelpWindowModel: def __init__(self): - self.history = [] # Track visited URLs - self.current_index = -1 # Current position in history + self.help_url = "https://docs.mantidproject.org/" - def add_url(self, url): - """Add a URL to the history, truncating forward history if necessary.""" - if self.current_index < len(self.history) - 1: - self.history = self.history[: self.current_index + 1] - self.history.append(url) - self.current_index += 1 - - def go_back(self): - """Navigate back in the history.""" - if self.current_index > 0: - self.current_index -= 1 - return self.history[self.current_index] - - def go_forward(self): - """Navigate forward in the history.""" - if self.current_index < len(self.history) - 1: - self.current_index += 1 - return self.history[self.current_index] - - def get_current_url(self): - """Get the current URL.""" - if self.current_index >= 0: - return self.history[self.current_index] - return None + def get_help_url(self): + """Get the help documentation URL.""" + return self.help_url diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py index aca5dd84a5f0..941b2f6ae7f1 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py @@ -1,70 +1,20 @@ -from helpwindowmodel import HelpModel -from helpwindowview import HelpView from qtpy.QtWidgets import QApplication +import sys +from .helpwindowview import HelpWindowView +from .helpwindowmodel import HelpWindowModel -class HelpPresenter: - _instance = None # Singleton instance for integration +class HelpWindowPresenter: + def __init__(self): + self.model = HelpWindowModel() + self.view = HelpWindowView(self) + self.app = QApplication(sys.argv) - @classmethod - def instance(cls): - """Ensure a single instance of HelpPresenter.""" - if cls._instance is None: - app = QApplication.instance() or QApplication([]) # noqa: F841 - model = HelpModel() - view = HelpView(None) - cls._instance = cls(model, view) - cls._instance.view = view - return cls._instance + def show_help_window(self): + """Show the help window.""" + self.view.display() + sys.exit(self.app.exec_()) - def __init__(self, model, view): - self.model = model - self.view = view - - def handle_url_changed(self, url): - """Handle URL changes in the view.""" - self.model.add_url(url.toString()) - self.update_navigation_buttons() - - def handle_go_back(self): - """Handle the back button click.""" - url = self.model.go_back() - if url: - self.view.set_url(url) - self.update_navigation_buttons() - - def handle_go_forward(self): - """Handle the forward button click.""" - url = self.model.go_forward() - if url: - self.view.set_url(url) - self.update_navigation_buttons() - - def handle_go_home(self): - """Handle the home button click.""" - url = self.model.history[0] if self.model.history else "about:blank" - self.view.set_url(url) - - def show_page(self, url): - """Load a page in the view.""" - self.model.add_url(url) - self.view.set_url(url) - self.update_navigation_buttons() - - def show_algorithm(self, name, version): - """Show an algorithm-specific help page.""" - base_url = "file:///path/to/docs/algorithms/" - algorithm_url = f"{base_url}{name}-v{version}.html" - self.show_page(algorithm_url) - - def show_concept(self, name): - """Show a concept-specific help page.""" - base_url = "file:///path/to/docs/concepts/" - concept_url = f"{base_url}{name}.html" - self.show_page(concept_url) - - def update_navigation_buttons(self): - """Update the state of navigation buttons in the view.""" - can_go_back = self.model.current_index > 0 - can_go_forward = self.model.current_index < len(self.model.history) - 1 - self.view.update_navigation_buttons(can_go_back, can_go_forward) + def on_close(self): + """Handle actions when the window is closed.""" + print("Help window closed.") diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py index 1ba8dfd60a08..626e281b3ef9 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -1,43 +1,30 @@ -from qtpy.QtCore import QUrl -from qtpy.QtWidgets import QVBoxLayout, QWidget, QPushButton, QHBoxLayout +from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QWidget from qtpy.QtWebEngineWidgets import QWebEngineView -class HelpView(QWidget): - def __init__(self, presenter, parent=None): - super().__init__(parent) +class HelpWindowView(QMainWindow): + def __init__(self, presenter): + super().__init__() self.presenter = presenter - - self.setWindowTitle("Mantid Help Window") - self.setGeometry(100, 100, 1200, 800) - - # Web view setup - self.webview = QWebEngineView() - self.webview.urlChanged.connect(self.presenter.handle_url_changed) - - # Navigation buttons - self.back_button = QPushButton("Back") - self.back_button.clicked.connect(self.presenter.handle_go_back) - self.forward_button = QPushButton("Forward") - self.forward_button.clicked.connect(self.presenter.handle_go_forward) - self.home_button = QPushButton("Home") - self.home_button.clicked.connect(self.presenter.handle_go_home) - - nav_layout = QHBoxLayout() - nav_layout.addWidget(self.back_button) - nav_layout.addWidget(self.forward_button) - nav_layout.addWidget(self.home_button) - - # Layout setup - main_layout = QVBoxLayout(self) - main_layout.addLayout(nav_layout) - main_layout.addWidget(self.webview) - - def set_url(self, url): - """Set the URL in the webview.""" - self.webview.setUrl(QUrl(url)) - - def update_navigation_buttons(self, can_go_back, can_go_forward): - """Enable or disable navigation buttons.""" - self.back_button.setEnabled(can_go_back) - self.forward_button.setEnabled(can_go_forward) + self.setWindowTitle("Python Help Window") + self.resize(800, 600) + + # Web view to display the help documentation + self.browser = QWebEngineView() + self.browser.setUrl("https://docs.mantidproject.org/") + + # Layout + layout = QVBoxLayout() + layout.addWidget(self.browser) + container = QWidget() + container.setLayout(layout) + self.setCentralWidget(container) + + def display(self): + """Show the help window.""" + self.show() + + def closeEvent(self, event): + """Handle the close event and notify the presenter.""" + self.presenter.on_close() + super().closeEvent(event) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index a2c396b5e105..44685e472e5d 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -1,3 +1,7 @@ +# Add the Python scripts directory to the build +set(PYTHON_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/mantid/qt/python/mantidqt/mantidqt/widgets/helpwindow) +set(ENV{PYTHONPATH} "$ENV{PYTHONPATH}:${PYTHON_SCRIPTS_DIR}") + set(SRC_FILES src/AddWorkspaceDialog.cpp src/AddWorkspaceMultiDialog.cpp diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 8ea40d15160c..3b697b8aeecc 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -18,6 +18,7 @@ namespace MantidQt { namespace API { /** +<<<<<<< Updated upstream * HelpWindow provides a centralized interface for displaying * help pages, algorithm details, and concepts. It supports both * the C++ HelpWindow and launching a Python-based HelpWindow. @@ -29,36 +30,36 @@ class EXPORT_OPT_MANTIDQT_COMMON HelpWindow : public QWidget { explicit HelpWindow(QWidget *parent = nullptr); /// Show a page by URL - static void showPage(const std::string &url = std::string()); - static void showPage(const QString &url); - static void showPage(const QUrl &url); + *HelpWindow class manages the launching of help pages and the Python Help Window.*/ + class EXPORT_OPT_MANTIDQT_COMMON HelpWindow { + public: + /// Show a help page by URL - /// Show algorithm help by name and version - static void showAlgorithm(const std::string &name = std::string(), const int version = -1); - static void showAlgorithm(const QString &name, const int version = -1); + static void showPage(const std::string &url = std::string()); + static void showPage(const QString &url); + static void showPage(const QUrl &url); - /// Show concept help by name - static void showConcept(const std::string &name = std::string()); - static void showConcept(const QString &name); + /// Show help for an algorithm + static void showAlgorithm(const std::string &name = std::string(), const int version = -1); + static void showAlgorithm(const QString &name, const int version = -1); - /// Show fit function help - static void showFitFunction(const std::string &name = std::string()); + /// Show help for a concept + static void showConcept(const std::string &name = std::string()); + static void showConcept(const QString &name); - /// Show custom interface help - static void showCustomInterface(const QString &name, const QString &area = QString(), - const QString §ion = QString()); - static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), - const std::string §ion = std::string()); + /// Show help for a fit function + static void showFitFunction(const std::string &name = std::string()); + static void showFitFunction(const QString &name); - /// Launch the Python-based HelpWindow with the current page - void launchPythonHelp(); + /// Show help for a custom interface + static void showCustomInterface(const QString &name, const QString &area = QString(), + const QString §ion = QString()); + static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), + const std::string §ion = std::string()); - /// Get the current page URL - QString currentPageUrl() const; - -private: - QString currentUrl; ///< Tracks the current URL displayed in the HelpWindow -}; + /// Launch the Python-based Help Window + static void launchPythonHelpWindow(); + }; } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/src/HelpWindow.cpp b/qt/widgets/common/src/HelpWindow.cpp index 37985d9a03f8..5f0736cc0797 100644 --- a/qt/widgets/common/src/HelpWindow.cpp +++ b/qt/widgets/common/src/HelpWindow.cpp @@ -13,126 +13,194 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" +<<<<<<< Updated upstream #include + == == == + = +#define PY_SSIZE_T_CLEAN +#undef slots +#include + + >>>>>>> Stashed changes #include #include #include #include -namespace MantidQt::API { -namespace { -/// static logger -Mantid::Kernel::Logger g_log("HelpWindow"); - -} // namespace - -using std::string; + namespace MantidQt::API { + namespace { + /// Static logger + Mantid::Kernel::Logger g_log("HelpWindow"); + } // namespace + + using std::string; + + void HelpWindow::showPage(const std::string &url) { showPage(QString::fromStdString(url)); } + + void HelpWindow::showPage(const QString &url) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showPage(url); + } else { + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid URL: " << url.toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening URL in default browser: " << validUrl.toString().toStdString() << "\n"; + } + } -void HelpWindow::showPage(const std::string &url) { showPage(QString(url.c_str())); } + void HelpWindow::showPage(const QUrl &url) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showPage(url); + } else { + if (!url.isValid()) { + g_log.error() << "Invalid QUrl: " << url.toString().toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(url); + g_log.debug() << "Opening URL in default browser: " << url.toString().toStdString() << "\n"; + } + } -void HelpWindow::showPage(const QString &url) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showPage(url); - } else { - g_log.error() << "Failed to launch help for page " << url.toStdString() << "\n"; + void HelpWindow::showAlgorithm(const std::string &name, const int version) { + showAlgorithm(QString::fromStdString(name), version); } -} - -void HelpWindow::showPage(const QUrl &url) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showPage(url); - } else { - g_log.error() << "Failed to launch help for page " << url.toString().toStdString() << "\n"; + + void HelpWindow::showAlgorithm(const QString &name, const int version) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showAlgorithm(name, version); + } else { + QString baseUrl = "https://docs.mantidproject.org/algorithms/"; + QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid algorithm URL: " << url.toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening algorithm help URL: " << validUrl.toString().toStdString() << "\n"; + } } -} - -void HelpWindow::showAlgorithm(const std::string &name, const int version) { - showAlgorithm(QString(name.c_str()), version); -} - -void HelpWindow::showAlgorithm(const QString &name, const int version) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showAlgorithm(name, version); - } else { - QString baseUrl = "https://docs.mantidproject.org/algorithms/"; - QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; - MantidDesktopServices::openUrl(QUrl(url)); - g_log.debug("Opening online help page:\n" + url.toStdString()); + + void HelpWindow::showConcept(const std::string &name) { showConcept(QString::fromStdString(name)); } + + void HelpWindow::showConcept(const QString &name) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showConcept(name); + } else { + QString baseUrl = "https://docs.mantidproject.org/concepts/"; + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid concept URL: " << url.toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening concept help URL: " << validUrl.toString().toStdString() << "\n"; + } } -} -void HelpWindow::showConcept(const std::string &name) { showConcept(QString(name.c_str())); } + void HelpWindow::showFitFunction(const std::string &name) { showFitFunction(QString::fromStdString(name)); } + + void HelpWindow::showFitFunction(const QString &name) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showFitFunction(name); + } else { + QString baseUrl = "https://docs.mantidproject.org/functions/"; + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid function URL: " << url.toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening fit function help URL: " << validUrl.toString().toStdString() << "\n"; + } + } -void HelpWindow::showConcept(const QString &name) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showConcept(name); - } else { - g_log.error() << "Failed to launch help for concept " << name.toStdString() << "\n"; + void HelpWindow::showCustomInterface(const std::string &name, const std::string &area, const std::string §ion) { + showCustomInterface(QString::fromStdString(name), QString::fromStdString(area), QString::fromStdString(section)); } -} - -void HelpWindow::showFitFunction(const std::string &name) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showFitFunction(name); - } else { - g_log.error() << "Failed to launch help for fit function " << name << "\n"; + + void HelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showCustomInterface(name, area, section); + } else { + QString baseUrl = "https://docs.mantidproject.org/interfaces/"; + if (!area.isEmpty()) { + baseUrl += area + "/"; + } + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid custom interface URL: " << url.toStdString() << "\n"; + return; + } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening custom interface help URL: " << validUrl.toString().toStdString() << "\n"; + } } -} - -void HelpWindow::showCustomInterface(const std::string &name, const std::string &area, const std::string §ion) { - showCustomInterface(QString::fromStdString(name), QString::fromStdString(area), QString::fromStdString(section)); -} - -void HelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showCustomInterface(name, area, section); - } else { - QString baseUrl = "https://docs.mantidproject.org/interfaces/"; - if (!area.toStdString().empty()) { - baseUrl += area + "/"; + + void HelpWindow::launchPythonHelpWindow() { + try { + // Initialize Python environment + Py_Initialize(); + boost::python::object main = boost::python::import("__main__"); + boost::python::object globals = main.attr("__dict__"); + + // Update the Python script to include the correct module path + const std::string pythonScript = R"( +import sys +sys.path.append('mantid/qt/python/mantidqt/mantidqt/widgets/helpwindow/') +from helpwindowpresenter import HelpWindowPresenter +presenter = HelpWindowPresenter() +presenter.show_help_window() +)"; + boost::python::exec(pythonScript.c_str(), globals, globals); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Error launching Python Help Window."); } - QString url = baseUrl + name + ".html"; - MantidDesktopServices::openUrl(QUrl(url)); - g_log.debug("Opening online help page:\n" + url.toStdString()); } -} - -void HelpWindow::launchPythonHelp() { - try { - boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); - boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); - - std::string currentPage = currentUrl.toStdString(); - boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), - mainNamespace); - } catch (const boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Failed to launch Python HelpWindow."); + + void HelpWindow::launchPythonHelp() { + try { + boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); + boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); + + std::string currentPage = currentUrl.toStdString(); + boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), + mainNamespace); + } catch (const boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Failed to launch Python HelpWindow."); + } } -} -HelpWindow::HelpWindow(QWidget *parent) : QWidget(parent), currentUrl("about:blank") { - auto *layout = new QVBoxLayout(this); + HelpWindow::HelpWindow(QWidget * parent) : QWidget(parent), currentUrl("about:blank") { + auto *layout = new QVBoxLayout(this); - QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); - connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); - layout->addWidget(pythonHelpButton); -} + QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); + connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); + layout->addWidget(pythonHelpButton); + } -QString HelpWindow::currentPageUrl() const { - return this->currentUrl; // Provide the current URL -} + QString HelpWindow::currentPageUrl() const { + return this->currentUrl; // Provide the current URL + } } // namespace MantidQt::API diff --git a/qt/widgets/common/src/SelectFunctionDialog.cpp b/qt/widgets/common/src/SelectFunctionDialog.cpp index a460f70115ff..465cd07464a0 100644 --- a/qt/widgets/common/src/SelectFunctionDialog.cpp +++ b/qt/widgets/common/src/SelectFunctionDialog.cpp @@ -250,7 +250,7 @@ void SelectFunctionDialog::helpClicked() const { if (!function.isEmpty()) { MantidQt::API::HelpWindow::showFitFunction(function.toStdString()); } else { // No function selected open fit function index - MantidQt::API::HelpWindow::showFitFunction(""); + MantidQt::API::HelpWindow::showFitFunction(QStringLiteral("")); } } From ef2349966b2818266b84645b9f3fab0cacb33ba1 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Tue, 10 Dec 2024 12:28:12 -0500 Subject: [PATCH 03/28] Most recent changes. --- .../inc/MantidQtWidgets/Common/HelpWindow.h | 53 +-- qt/widgets/common/src/HelpWindow.cpp | 304 +++++++++--------- 2 files changed, 178 insertions(+), 179 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 3b697b8aeecc..3f764059f0bf 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -18,7 +18,6 @@ namespace MantidQt { namespace API { /** -<<<<<<< Updated upstream * HelpWindow provides a centralized interface for displaying * help pages, algorithm details, and concepts. It supports both * the C++ HelpWindow and launching a Python-based HelpWindow. @@ -30,36 +29,40 @@ class EXPORT_OPT_MANTIDQT_COMMON HelpWindow : public QWidget { explicit HelpWindow(QWidget *parent = nullptr); /// Show a page by URL - *HelpWindow class manages the launching of help pages and the Python Help Window.*/ - class EXPORT_OPT_MANTIDQT_COMMON HelpWindow { - public: - /// Show a help page by URL + static void showPage(const std::string &url = std::string()); + static void showPage(const QString &url); + static void showPage(const QUrl &url); - static void showPage(const std::string &url = std::string()); - static void showPage(const QString &url); - static void showPage(const QUrl &url); + /// Show help for an algorithm + static void showAlgorithm(const std::string &name = std::string(), const int version = -1); + static void showAlgorithm(const QString &name, const int version = -1); - /// Show help for an algorithm - static void showAlgorithm(const std::string &name = std::string(), const int version = -1); - static void showAlgorithm(const QString &name, const int version = -1); + /// Show help for a concept + static void showConcept(const std::string &name = std::string()); + static void showConcept(const QString &name); - /// Show help for a concept - static void showConcept(const std::string &name = std::string()); - static void showConcept(const QString &name); + /// Show help for a fit function + static void showFitFunction(const std::string &name = std::string()); + static void showFitFunction(const QString &name); - /// Show help for a fit function - static void showFitFunction(const std::string &name = std::string()); - static void showFitFunction(const QString &name); + /// Show help for a custom interface + static void showCustomInterface(const QString &name, const QString &area = QString(), + const QString §ion = QString()); + static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), + const std::string §ion = std::string()); - /// Show help for a custom interface - static void showCustomInterface(const QString &name, const QString &area = QString(), - const QString §ion = QString()); - static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), - const std::string §ion = std::string()); + /// Launch the Python-based Help Window + static void launchPythonHelpWindow(); - /// Launch the Python-based Help Window - static void launchPythonHelpWindow(); - }; + /// Launch a specific Python help page + void launchPythonHelp(); + + /// Get the current page URL + QString currentPageUrl() const; + +private: + QString currentUrl; // Stores the current URL +}; } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/src/HelpWindow.cpp b/qt/widgets/common/src/HelpWindow.cpp index 5f0736cc0797..d3459d713e55 100644 --- a/qt/widgets/common/src/HelpWindow.cpp +++ b/qt/widgets/common/src/HelpWindow.cpp @@ -13,194 +13,190 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" -<<<<<<< Updated upstream #include - == == == - = #define PY_SSIZE_T_CLEAN #undef slots #include - >>>>>>> Stashed changes #include #include #include #include - namespace MantidQt::API { - namespace { - /// Static logger - Mantid::Kernel::Logger g_log("HelpWindow"); - } // namespace - - using std::string; - - void HelpWindow::showPage(const std::string &url) { showPage(QString::fromStdString(url)); } - - void HelpWindow::showPage(const QString &url) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showPage(url); - } else { - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening URL in default browser: " << validUrl.toString().toStdString() << "\n"; +namespace MantidQt::API { +namespace { +/// Static logger +Mantid::Kernel::Logger g_log("HelpWindow"); +} // namespace + +using std::string; + +void HelpWindow::showPage(const std::string &url) { showPage(QString::fromStdString(url)); } + +void HelpWindow::showPage(const QString &url) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showPage(url); + } else { + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid URL: " << url.toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening URL in default browser: " << validUrl.toString().toStdString() << "\n"; } - - void HelpWindow::showPage(const QUrl &url) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showPage(url); - } else { - if (!url.isValid()) { - g_log.error() << "Invalid QUrl: " << url.toString().toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(url); - g_log.debug() << "Opening URL in default browser: " << url.toString().toStdString() << "\n"; +} + +void HelpWindow::showPage(const QUrl &url) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showPage(url); + } else { + if (!url.isValid()) { + g_log.error() << "Invalid QUrl: " << url.toString().toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(url); + g_log.debug() << "Opening URL in default browser: " << url.toString().toStdString() << "\n"; } - - void HelpWindow::showAlgorithm(const std::string &name, const int version) { - showAlgorithm(QString::fromStdString(name), version); - } - - void HelpWindow::showAlgorithm(const QString &name, const int version) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showAlgorithm(name, version); - } else { - QString baseUrl = "https://docs.mantidproject.org/algorithms/"; - QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid algorithm URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening algorithm help URL: " << validUrl.toString().toStdString() << "\n"; +} + +void HelpWindow::showAlgorithm(const std::string &name, const int version) { + showAlgorithm(QString::fromStdString(name), version); +} + +void HelpWindow::showAlgorithm(const QString &name, const int version) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showAlgorithm(name, version); + } else { + QString baseUrl = "https://docs.mantidproject.org/algorithms/"; + QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid algorithm URL: " << url.toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening algorithm help URL: " << validUrl.toString().toStdString() << "\n"; } - - void HelpWindow::showConcept(const std::string &name) { showConcept(QString::fromStdString(name)); } - - void HelpWindow::showConcept(const QString &name) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showConcept(name); - } else { - QString baseUrl = "https://docs.mantidproject.org/concepts/"; - QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid concept URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening concept help URL: " << validUrl.toString().toStdString() << "\n"; +} + +void HelpWindow::showConcept(const std::string &name) { showConcept(QString::fromStdString(name)); } + +void HelpWindow::showConcept(const QString &name) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showConcept(name); + } else { + QString baseUrl = "https://docs.mantidproject.org/concepts/"; + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid concept URL: " << url.toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening concept help URL: " << validUrl.toString().toStdString() << "\n"; } - - void HelpWindow::showFitFunction(const std::string &name) { showFitFunction(QString::fromStdString(name)); } - - void HelpWindow::showFitFunction(const QString &name) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showFitFunction(name); - } else { - QString baseUrl = "https://docs.mantidproject.org/functions/"; - QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid function URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening fit function help URL: " << validUrl.toString().toStdString() << "\n"; +} + +void HelpWindow::showFitFunction(const std::string &name) { showFitFunction(QString::fromStdString(name)); } + +void HelpWindow::showFitFunction(const QString &name) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showFitFunction(name); + } else { + QString baseUrl = "https://docs.mantidproject.org/functions/"; + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid function URL: " << url.toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening fit function help URL: " << validUrl.toString().toStdString() << "\n"; } - - void HelpWindow::showCustomInterface(const std::string &name, const std::string &area, const std::string §ion) { - showCustomInterface(QString::fromStdString(name), QString::fromStdString(area), QString::fromStdString(section)); - } - - void HelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { - InterfaceManager interfaceManager; - MantidHelpInterface *gui = interfaceManager.createHelpWindow(); - if (gui) { - gui->showCustomInterface(name, area, section); - } else { - QString baseUrl = "https://docs.mantidproject.org/interfaces/"; - if (!area.isEmpty()) { - baseUrl += area + "/"; - } - QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid custom interface URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening custom interface help URL: " << validUrl.toString().toStdString() << "\n"; +} + +void HelpWindow::showCustomInterface(const std::string &name, const std::string &area, const std::string §ion) { + showCustomInterface(QString::fromStdString(name), QString::fromStdString(area), QString::fromStdString(section)); +} + +void HelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { + InterfaceManager interfaceManager; + MantidHelpInterface *gui = interfaceManager.createHelpWindow(); + if (gui) { + gui->showCustomInterface(name, area, section); + } else { + QString baseUrl = "https://docs.mantidproject.org/interfaces/"; + if (!area.isEmpty()) { + baseUrl += area + "/"; + } + QString url = baseUrl + name + ".html"; + QUrl validUrl = QUrl::fromUserInput(url); + if (!validUrl.isValid()) { + g_log.error() << "Invalid custom interface URL: " << url.toStdString() << "\n"; + return; } + MantidDesktopServices::openUrl(validUrl); + g_log.debug() << "Opening custom interface help URL: " << validUrl.toString().toStdString() << "\n"; } +} - void HelpWindow::launchPythonHelpWindow() { - try { - // Initialize Python environment - Py_Initialize(); - boost::python::object main = boost::python::import("__main__"); - boost::python::object globals = main.attr("__dict__"); +void HelpWindow::launchPythonHelpWindow() { + try { + // Initialize Python environment + Py_Initialize(); + boost::python::object main = boost::python::import("__main__"); + boost::python::object globals = main.attr("__dict__"); - // Update the Python script to include the correct module path - const std::string pythonScript = R"( + // Update the Python script to include the correct module path + const std::string pythonScript = R"( import sys sys.path.append('mantid/qt/python/mantidqt/mantidqt/widgets/helpwindow/') from helpwindowpresenter import HelpWindowPresenter presenter = HelpWindowPresenter() presenter.show_help_window() )"; - boost::python::exec(pythonScript.c_str(), globals, globals); - } catch (boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Error launching Python Help Window."); - } + boost::python::exec(pythonScript.c_str(), globals, globals); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Error launching Python Help Window."); } - - void HelpWindow::launchPythonHelp() { - try { - boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); - boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); - - std::string currentPage = currentUrl.toStdString(); - boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), - mainNamespace); - } catch (const boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Failed to launch Python HelpWindow."); - } +} + +void HelpWindow::launchPythonHelp() { + try { + boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); + boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); + + std::string currentPage = currentUrl.toStdString(); + boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), + mainNamespace); + } catch (const boost::python::error_already_set &) { + PyErr_Print(); + g_log.error("Failed to launch Python HelpWindow."); } +} - HelpWindow::HelpWindow(QWidget * parent) : QWidget(parent), currentUrl("about:blank") { - auto *layout = new QVBoxLayout(this); +HelpWindow::HelpWindow(QWidget *parent) : QWidget(parent), currentUrl("about:blank") { + auto *layout = new QVBoxLayout(this); - QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); - connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); - layout->addWidget(pythonHelpButton); - } + QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); + connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); + layout->addWidget(pythonHelpButton); +} - QString HelpWindow::currentPageUrl() const { - return this->currentUrl; // Provide the current URL - } +QString HelpWindow::currentPageUrl() const { + return this->currentUrl; // Provide the current URL +} } // namespace MantidQt::API From 7f8521901103231add8c4ae0367c322b74980f8d Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 11 Dec 2024 13:55:12 -0500 Subject: [PATCH 04/28] Updating branch with latest changes --- .../inc/MantidQtWidgets/Common/HelpWindow.h | 4 +--- .../MantidQtWidgets/Common/InterfaceManager.h | 8 +++++-- qt/widgets/common/src/HelpWindow.cpp | 8 ++----- qt/widgets/common/src/InterfaceManager.cpp | 24 ++++++++++++++----- .../inc/MantidQtWidgets/MplCpp/Colormap.h | 4 ++++ 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 3f764059f0bf..14b5ba4bf257 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -8,12 +8,10 @@ #include "MantidQtWidgets/Common/DllOption.h" #include +#include #include #include -// Forward declarations -class QUrl; - namespace MantidQt { namespace API { diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index 7dd581ee34d9..1dab4edea02d 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -9,8 +9,6 @@ //---------------------------------- // Includes //---------------------------------- -#include - #include "DllOption.h" #include "MantidKernel/Instantiator.h" @@ -20,6 +18,12 @@ #include #include +#pragma push_macro("slots") +#undef slots +#include +#include +#pragma pop_macro("slots") + //---------------------------------- // Qt Forward declarations //---------------------------------- diff --git a/qt/widgets/common/src/HelpWindow.cpp b/qt/widgets/common/src/HelpWindow.cpp index d3459d713e55..94c2dd90eb5c 100644 --- a/qt/widgets/common/src/HelpWindow.cpp +++ b/qt/widgets/common/src/HelpWindow.cpp @@ -14,14 +14,10 @@ #include "MantidQtWidgets/Common/MantidHelpInterface.h" #include -#define PY_SSIZE_T_CLEAN -#undef slots -#include - #include #include -#include -#include + +#define PY_SSIZE_T_CLEAN namespace MantidQt::API { namespace { diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 26c65a6c958b..066f77b713e0 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -1,8 +1,6 @@ // Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, -// NScD Oak Ridge National Laboratory, European Spallation Source, -// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + //---------------------------------- // Includes @@ -31,24 +29,38 @@ using Mantid::Kernel::AbstractInstantiator; using MantidQt::MantidWidgets::MantidHelpWindow; namespace { -// static logger +// Static logger Mantid::Kernel::Logger g_log("InterfaceManager"); // Load libraries once std::once_flag DLLS_LOADED; -// Track if message saying offline help is unavailable has been shown +// Track if the offline help message has been displayed bool offlineHelpMsgDisplayed = false; } // namespace -// Initialise HelpWindow factory +// Initialize HelpWindow factory Mantid::Kernel::AbstractInstantiator *InterfaceManager::m_helpViewer = nullptr; //---------------------------------- // Public member functions //---------------------------------- +AlgorithmDialog *InterfaceManager::createDialogFromName(const QString &algorithmName, const int version, + QWidget *parent, bool forScript, + const QHash &presetValues, + const QString &optionalMsg, const QStringList &enabled, + const QStringList &disabled) { + auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(algorithmName.toStdString(), version); + if (!alg) { + g_log.error() << "Failed to create algorithm: " << algorithmName.toStdString() << "\n"; + return nullptr; + } + return createDialog(std::shared_ptr(alg), parent, forScript, presetValues, optionalMsg, + enabled, disabled); +} + /** * Show a help page using the default or Python-based HelpWindow * @param url :: URL of the page to be displayed @@ -166,7 +178,7 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } else { auto *interface = m_helpViewer->createUnwrappedInstance(); if (!interface) { - g_log.error("Error creating help window"); + g_log.error("Error creating help window."); } return interface; } diff --git a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h index 30208515bf8e..c79091d01013 100644 --- a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h +++ b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h @@ -11,7 +11,11 @@ #undef slots #include "MantidQtWidgets/Common/Python/Object.h" #pragma pop_macro("slots") +#include #include +#include +#include +#include namespace MantidQt { namespace Widgets { From af660606a863528f294bb6f1376b8ef099e6ce03 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Thu, 12 Dec 2024 16:58:02 -0500 Subject: [PATCH 05/28] Make qtassistant a compile time option This removes the pointer to the qtassistant wrapper as dependent on the variable QT_DOCS. The default behavior is to keep the current functionality. --- CMakeLists.txt | 2 ++ docs/CMakeLists.txt | 1 - qt/widgets/common/CMakeLists.txt | 5 ++++ .../MantidQtWidgets/Common/MantidHelpWindow.h | 12 +++++++++- qt/widgets/common/src/MantidHelpWindow.cpp | 24 +++++++++++++++++++ 5 files changed, 42 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d550859d9e..1c793739687e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,8 @@ endif() # Docs requirements option(ENABLE_DOCS "Enable Building user and developer documentation" ON) if(ENABLE_DOCS) + option(DOCS_QTHELP "If enabled add a target to build the qthelp documentation for qtassistant" ON) + find_package(Sphinx REQUIRED) # run python to see if the theme is installed execute_process( diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 238d485d76e7..c47d6707ff10 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -9,7 +9,6 @@ set(DOCS_MATH_EXT ) set_property(CACHE DOCS_MATH_EXT PROPERTY STRINGS "sphinx.ext.imgmath" "sphinx.ext.mathjax") option(DOCS_PLOTDIRECTIVE "If enabled include plots generated with the plot directive. " OFF) -option(DOCS_QTHELP "If enabled add a target to build the qthelp documentation" ON) option(SPHINX_WARNINGS_AS_ERRORS "non-zero exit if there are sphinx warnings" ON) option(SPHINX_FRESH_ENV "Don't use a saved environment, but rebuild it completely" ON) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 44685e472e5d..1ba62b4f09cb 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -701,6 +701,11 @@ mtd_add_qt_library( OSX_INSTALL_RPATH @loader_path/../MacOS @loader_path/../Frameworks LINUX_INSTALL_RPATH "\$ORIGIN/../${WORKBENCH_LIB_DIR}" ) +# add an extra define to use pqhelpwindow which wraps qtassistant +if(DOCS_QTHELP) + # warning - this is assuming that the output is qt5 only + target_compile_definitions(MantidQtWidgetsCommonQt5 PUBLIC -DDOCS_QTHELP) +endif() set(TEST_FILES test/AlgorithmHintStrategyTest.h diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h index 1d503ff3dddb..d914aa1cd659 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h @@ -16,7 +16,9 @@ class QHelpEngine; class QString; class QWidget; +#ifdef DOCS_QTHELP class pqHelpWindow; +#endif namespace MantidQt { namespace MantidWidgets { @@ -25,7 +27,13 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf Q_OBJECT public: - static bool helpWindowExists() { return !g_helpWindow.isNull(); } + static bool helpWindowExists() { +#ifdef DOCS_QTHELP + return !g_helpWindow.isNull(); +#else + throw std::runtime_error("TODO: Not implemented yet"); +#endif + } MantidHelpWindow(const Qt::WindowFlags &flags = Qt::WindowFlags()); @@ -49,8 +57,10 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf /// The full path of the collection file. std::string m_collectionFile; +#ifdef DOCS_QTHELP /// The window that renders the help information static QPointer g_helpWindow; +#endif /// Whether this is the very first startup of the helpwindow. bool m_firstRun; diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index 32c04ab157ed..df22350e4b4e 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -11,7 +11,9 @@ #include "MantidKernel/RegistrationHelper.h" #include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidDesktopServices.h" +#ifdef DOCS_QTHELP #include "MantidQtWidgets/Common/pqHelpWindow.h" +#endif #include #include #include @@ -43,8 +45,10 @@ namespace { Mantid::Kernel::Logger g_log("MantidHelpWindow"); } // namespace +#ifdef DOCS_QTHELP // initialise the help window QPointer MantidHelpWindow::g_helpWindow; +#endif /// name of the collection file itself const QString COLLECTION_FILE("MantidProject.qhc"); @@ -87,17 +91,29 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) g_log.debug("helpengine.setupData() returned false"); // create a new help window +#ifdef DOCS_QTHELP g_helpWindow = new pqHelpWindow(helpEngine, this, flags); g_helpWindow->setWindowTitle(QString("Mantid - Help")); g_helpWindow->setWindowIcon(QIcon(":/images/MantidIcon.ico")); +#else + throw std::runtime_error("TODO not implemented yet"); +#endif // show the home page on startup auto registeredDocs = helpEngine->registeredDocumentations(); if (registeredDocs.size() > 0) { +#ifdef DOCS_QTHELP g_helpWindow->showHomePage(registeredDocs[0]); +#else + throw std::runtime_error("TODO not implemented yet"); +#endif } +#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); +#else + throw std::runtime_error("TODO not implemented yet"); +#endif } else { g_log.information("Without collection file redirecting help to default web browser"); } @@ -107,11 +123,15 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) void MantidHelpWindow::showHelp(const QString &url) { g_log.debug() << "open help window for \"" << url.toStdString() << "\"\n"; // bring up the help window if it is showing +#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); if (!url.isEmpty()) { g_helpWindow->showPage(url); } +#else + throw std::runtime_error("TODO not implemented yet"); +#endif } void MantidHelpWindow::openWebpage(const QUrl &url) { @@ -283,8 +303,12 @@ void MantidHelpWindow::shutdown() { // Deleting the object ensures the help engine's destructor is called and // avoids a segfault when workbench is closed if (helpWindowExists()) { +#ifdef DOCS_QTHELP g_helpWindow->setAttribute(Qt::WA_DeleteOnClose); g_helpWindow->close(); +#else + throw std::runtime_error("TODO not implemented yet"); +#endif } else { g_log.warning("Something really wrong in MantidHelpWindow::shutdown()"); } From 1bda78b575e934a769751116da8cdbddb225e429 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Fri, 13 Dec 2024 15:01:42 -0500 Subject: [PATCH 06/28] Hopefully this is a compile time implementation --- .../widgets/helpwindow/helpwindowbridge.py | 16 + qt/widgets/common/CMakeLists.txt | 19 - .../inc/MantidQtWidgets/Common/HelpWindow.h | 40 +-- .../MantidQtWidgets/Common/InterfaceManager.h | 27 +- .../MantidQtWidgets/Common/MantidHelpWindow.h | 12 +- .../MantidQtWidgets/Common/PythonHelpBridge.h | 8 + qt/widgets/common/src/HelpWindow.cpp | 125 +------ qt/widgets/common/src/InterfaceManager.cpp | 333 +++++++++++++----- qt/widgets/common/src/MantidHelpWindow.cpp | 24 -- qt/widgets/common/src/PythonHelpBridge.cpp | 27 ++ .../common/src/SelectFunctionDialog.cpp | 2 +- .../inc/MantidQtWidgets/MplCpp/Colormap.h | 4 - 12 files changed, 337 insertions(+), 300 deletions(-) create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py create mode 100644 qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h create mode 100644 qt/widgets/common/src/PythonHelpBridge.cpp diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py new file mode 100644 index 000000000000..255576ff8d13 --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py @@ -0,0 +1,16 @@ +from mantidqt.widgets.helpwindow.helpwindowpresenter import HelpWindowPresenter +from qtpy.QtCore import QUrl + +_presenter = None + + +def show_help_page(relative_url): + """ + Show the help window at the given relative URL path, e.g. "algorithms/Load-v1.html". + """ + global _presenter + if _presenter is None: + _presenter = HelpWindowPresenter() + full_url = "https://docs.mantidproject.org/" + relative_url + _presenter.view.browser.setUrl(QUrl(full_url)) + _presenter.show_help_window() diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 1ba62b4f09cb..aa755347bbcc 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -1,7 +1,3 @@ -# Add the Python scripts directory to the build -set(PYTHON_SCRIPTS_DIR ${CMAKE_SOURCE_DIR}/mantid/qt/python/mantidqt/mantidqt/widgets/helpwindow) -set(ENV{PYTHONPATH} "$ENV{PYTHONPATH}:${PYTHON_SCRIPTS_DIR}") - set(SRC_FILES src/AddWorkspaceDialog.cpp src/AddWorkspaceMultiDialog.cpp @@ -162,7 +158,6 @@ set(SRC_FILES src/Python/Sip.cpp src/Python/QHashToDict.cpp ) - set(QT5_MOC_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.h inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.h @@ -265,7 +260,6 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h inc/MantidQtWidgets/Common/QtPropertyBrowser/WorkspaceEditorFactory.h ) - # Include files aren't required, but this makes them appear in Visual Studio set(QT5_INC_FILES ${QT5_MOC_FILES} @@ -352,7 +346,6 @@ set(QT5_INC_FILES inc/MantidQtWidgets/Common/Python/Object.h inc/MantidQtWidgets/Common/Python/QHashToDict.h ) - set(QT5_UI_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.ui inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.ui @@ -373,7 +366,6 @@ set(QT5_UI_FILES inc/MantidQtWidgets/Common/SlitCalculator.ui inc/MantidQtWidgets/Common/UserFunctionDialog.ui ) - set(MOC_FILES inc/MantidQtWidgets/Common/AlgorithmDialog.h inc/MantidQtWidgets/Common/AlgorithmHistoryWindow.h @@ -480,7 +472,6 @@ set(MOC_FILES inc/MantidQtWidgets/Common/QtPropertyBrowser/qtbuttonpropertybrowser.h inc/MantidQtWidgets/Common/QtPropertyBrowser/qtgroupboxpropertybrowser.h ) - # Include files aren't required, but this makes them appear in Visual Studio set(INC_FILES ${MOC_FILES} @@ -608,7 +599,6 @@ set(INC_FILES inc/MantidQtWidgets/Common/Batch/MockJobTreeView.h inc/MantidQtWidgets/Common/Python/Object.h ) - set(UI_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.ui inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.ui @@ -633,13 +623,10 @@ set(UI_FILES inc/MantidQtWidgets/Common/UserFunctionDialog.ui inc/MantidQtWidgets/Common/pqHelpWindow.ui ) - set(TARGET_LIBRARIES ${CORE_MANTIDLIBS} ${POCO_LIBRARIES} ${Boost_LIBRARIES}) - if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(APPEND TARGET_LIBRARIES "-framework CoreFoundation") endif() - # Target Additional components for this module find_package( Qt5 ${QT_MIN_VERSION} @@ -668,7 +655,6 @@ else() message(FATAL_ERROR "Unable to find suitable module for web widgets. Tried: WebEnginewidgets, WebKitWidgets") endif() endif() - # If not sip header is defined we need to generate one with sip-module if(SIP_INCLUDE_DIR AND EXISTS ${SIP_INCLUDE_DIR}/sip.h) set(_sip_include_dir ${SIP_INCLUDE_DIR}) @@ -682,7 +668,6 @@ else() COMMENT "Generating sip.h for common widgets target" ) endif() - mtd_add_qt_library( TARGET_NAME MantidQtWidgetsCommon QT_VERSION 5 @@ -743,9 +728,7 @@ set(TEST_FILES test/WorkspacePresenter/ADSAdapterTest.h test/WorkspacePresenter/WorkspacePresenterTest.h ) - set(CXXTEST_EXTRA_HEADER_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/test/WidgetsCommonTestInitialization.h) - set(QT5_TEST_FILES test/AlgorithmRunnerTest.h test/BatchAlgorithmRunnerTest.h @@ -784,7 +767,6 @@ set(QT5_TEST_FILES test/WorkspacePresenter/ADSAdapterTest.h test/WorkspacePresenter/WorkspacePresenterTest.h ) - if(MANTID_FRAMEWORK_LIB STREQUAL "BUILD") mtd_add_qt_tests( TARGET_NAME MantidQtWidgetsCommonTest @@ -801,7 +783,6 @@ if(MANTID_FRAMEWORK_LIB STREQUAL "BUILD") MTD_QT_LINK_LIBS MantidQtWidgetsCommon PARENT_DEPENDENCIES GUITests ) - add_framework_test_helpers(MantidQtWidgetsCommonTestQt5) pyunittest_add_test(${CMAKE_CURRENT_SOURCE_DIR} MantidQtWidgetsCommonPyTest ${TEST_PY_FILES}) endif() diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 14b5ba4bf257..8ce46c921f62 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -1,3 +1,4 @@ + // Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2013 ISIS Rutherford Appleton Laboratory UKRI, @@ -8,59 +9,28 @@ #include "MantidQtWidgets/Common/DllOption.h" #include -#include -#include #include +// forward declarations +class QUrl; + namespace MantidQt { namespace API { -/** - * HelpWindow provides a centralized interface for displaying - * help pages, algorithm details, and concepts. It supports both - * the C++ HelpWindow and launching a Python-based HelpWindow. - */ -class EXPORT_OPT_MANTIDQT_COMMON HelpWindow : public QWidget { - Q_OBJECT - +class EXPORT_OPT_MANTIDQT_COMMON HelpWindow { public: - explicit HelpWindow(QWidget *parent = nullptr); - - /// Show a page by URL static void showPage(const std::string &url = std::string()); static void showPage(const QString &url); static void showPage(const QUrl &url); - - /// Show help for an algorithm static void showAlgorithm(const std::string &name = std::string(), const int version = -1); static void showAlgorithm(const QString &name, const int version = -1); - - /// Show help for a concept static void showConcept(const std::string &name = std::string()); static void showConcept(const QString &name); - - /// Show help for a fit function static void showFitFunction(const std::string &name = std::string()); - static void showFitFunction(const QString &name); - - /// Show help for a custom interface static void showCustomInterface(const QString &name, const QString &area = QString(), const QString §ion = QString()); static void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), const std::string §ion = std::string()); - - /// Launch the Python-based Help Window - static void launchPythonHelpWindow(); - - /// Launch a specific Python help page - void launchPythonHelp(); - - /// Get the current page URL - QString currentPageUrl() const; - -private: - QString currentUrl; // Stores the current URL }; - } // namespace API } // namespace MantidQt diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index 1dab4edea02d..ff2ca5e6e131 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -18,12 +18,6 @@ #include #include -#pragma push_macro("slots") -#undef slots -#include -#include -#pragma pop_macro("slots") - //---------------------------------- // Qt Forward declarations //---------------------------------- @@ -110,12 +104,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Close the active help window void closeHelpWindow(); - /** - * Launch the Python-based HelpWindow - * @param url :: URL to pass to the Python HelpWindow - */ - void launchPythonHelp(const QString &url); - /** * Registration function for the help window factory. * @param factory the factory instance @@ -135,10 +123,19 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { virtual ~InterfaceManager(); private: - void notifyExistingInterfaces(UserSubWindow *newWindow); - /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; + + void notifyExistingInterfaces(UserSubWindow *newWindow); + +#ifdef USE_PYTHON_WEB_HELP + // Placeholder function that you would implement to run the Python-based help window + void launchPythonHelpWindow(const QString &relativePage); + void launchPythonHelpWindowForAlgorithm(const QString &name, int version = -1); + void launchPythonHelpWindowForConcept(const QString &name); + void launchPythonHelpWindowForFitFunction(const QString &name); + void launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, const QString §ion); +#endif }; } // namespace API @@ -149,6 +146,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { namespace { \ Mantid::Kernel::RegistrationHelper \ register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( \ - new Mantid::Kernel::Instantiator())), \ + new Mantid::Kernel::Instantiator())), \ 0)); \ } diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h index d914aa1cd659..1d503ff3dddb 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h @@ -16,9 +16,7 @@ class QHelpEngine; class QString; class QWidget; -#ifdef DOCS_QTHELP class pqHelpWindow; -#endif namespace MantidQt { namespace MantidWidgets { @@ -27,13 +25,7 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf Q_OBJECT public: - static bool helpWindowExists() { -#ifdef DOCS_QTHELP - return !g_helpWindow.isNull(); -#else - throw std::runtime_error("TODO: Not implemented yet"); -#endif - } + static bool helpWindowExists() { return !g_helpWindow.isNull(); } MantidHelpWindow(const Qt::WindowFlags &flags = Qt::WindowFlags()); @@ -57,10 +49,8 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf /// The full path of the collection file. std::string m_collectionFile; -#ifdef DOCS_QTHELP /// The window that renders the help information static QPointer g_helpWindow; -#endif /// Whether this is the very first startup of the helpwindow. bool m_firstRun; diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h new file mode 100644 index 000000000000..6d1084094387 --- /dev/null +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h @@ -0,0 +1,8 @@ +#pragma once +#include + +class PythonHelpBridge { +public: + PythonHelpBridge(); + void showHelpPage(const std::string &relative_url); +}; diff --git a/qt/widgets/common/src/HelpWindow.cpp b/qt/widgets/common/src/HelpWindow.cpp index 94c2dd90eb5c..1d7063bf257d 100644 --- a/qt/widgets/common/src/HelpWindow.cpp +++ b/qt/widgets/common/src/HelpWindow.cpp @@ -4,7 +4,6 @@ // NScD Oak Ridge National Laboratory, European Spallation Source, // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + - #include "MantidQtWidgets/Common/HelpWindow.h" #include "MantidKernel/ConfigService.h" #include "MantidKernel/Exception.h" @@ -13,21 +12,20 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" -#include #include -#include - -#define PY_SSIZE_T_CLEAN +#include +#include namespace MantidQt::API { namespace { -/// Static logger +/// static logger Mantid::Kernel::Logger g_log("HelpWindow"); + } // namespace using std::string; -void HelpWindow::showPage(const std::string &url) { showPage(QString::fromStdString(url)); } +void HelpWindow::showPage(const std::string &url) { showPage(QString(url.c_str())); } void HelpWindow::showPage(const QString &url) { InterfaceManager interfaceManager; @@ -35,13 +33,7 @@ void HelpWindow::showPage(const QString &url) { if (gui) { gui->showPage(url); } else { - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening URL in default browser: " << validUrl.toString().toStdString() << "\n"; + g_log.error() << "Failed to launch help for page " << url.toStdString() << "\n"; } } @@ -51,17 +43,12 @@ void HelpWindow::showPage(const QUrl &url) { if (gui) { gui->showPage(url); } else { - if (!url.isValid()) { - g_log.error() << "Invalid QUrl: " << url.toString().toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(url); - g_log.debug() << "Opening URL in default browser: " << url.toString().toStdString() << "\n"; + g_log.error() << "Failed to launch help for page " << url.toString().toStdString() << "\n"; } } void HelpWindow::showAlgorithm(const std::string &name, const int version) { - showAlgorithm(QString::fromStdString(name), version); + showAlgorithm(QString(name.c_str()), version); } void HelpWindow::showAlgorithm(const QString &name, const int version) { @@ -70,19 +57,15 @@ void HelpWindow::showAlgorithm(const QString &name, const int version) { if (gui) { gui->showAlgorithm(name, version); } else { + // Open online help QString baseUrl = "https://docs.mantidproject.org/algorithms/"; QString url = baseUrl + name + "-v" + QString::number(version) + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid algorithm URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening algorithm help URL: " << validUrl.toString().toStdString() << "\n"; + MantidDesktopServices::openUrl(QUrl(url)); + g_log.debug("Opening online help page:\n" + url.toStdString()); } } -void HelpWindow::showConcept(const std::string &name) { showConcept(QString::fromStdString(name)); } +void HelpWindow::showConcept(const std::string &name) { showConcept(QString(name.c_str())); } void HelpWindow::showConcept(const QString &name) { InterfaceManager interfaceManager; @@ -90,35 +73,17 @@ void HelpWindow::showConcept(const QString &name) { if (gui) { gui->showConcept(name); } else { - QString baseUrl = "https://docs.mantidproject.org/concepts/"; - QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid concept URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening concept help URL: " << validUrl.toString().toStdString() << "\n"; + g_log.error() << "Failed to launch help for concept " << name.toStdString() << "\n"; } } -void HelpWindow::showFitFunction(const std::string &name) { showFitFunction(QString::fromStdString(name)); } - -void HelpWindow::showFitFunction(const QString &name) { +void HelpWindow::showFitFunction(const std::string &name) { InterfaceManager interfaceManager; MantidHelpInterface *gui = interfaceManager.createHelpWindow(); if (gui) { gui->showFitFunction(name); } else { - QString baseUrl = "https://docs.mantidproject.org/functions/"; - QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid function URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening fit function help URL: " << validUrl.toString().toStdString() << "\n"; + g_log.error() << "Failed to launch help for fit function " << name << "\n"; } } @@ -132,67 +97,15 @@ void HelpWindow::showCustomInterface(const QString &name, const QString &area, c if (gui) { gui->showCustomInterface(name, area, section); } else { + // Open online help QString baseUrl = "https://docs.mantidproject.org/interfaces/"; - if (!area.isEmpty()) { + if (!area.toStdString().empty()) { baseUrl += area + "/"; } QString url = baseUrl + name + ".html"; - QUrl validUrl = QUrl::fromUserInput(url); - if (!validUrl.isValid()) { - g_log.error() << "Invalid custom interface URL: " << url.toStdString() << "\n"; - return; - } - MantidDesktopServices::openUrl(validUrl); - g_log.debug() << "Opening custom interface help URL: " << validUrl.toString().toStdString() << "\n"; + MantidDesktopServices::openUrl(QUrl(url)); + g_log.debug("Opening online help page:\n" + url.toStdString()); } } -void HelpWindow::launchPythonHelpWindow() { - try { - // Initialize Python environment - Py_Initialize(); - boost::python::object main = boost::python::import("__main__"); - boost::python::object globals = main.attr("__dict__"); - - // Update the Python script to include the correct module path - const std::string pythonScript = R"( -import sys -sys.path.append('mantid/qt/python/mantidqt/mantidqt/widgets/helpwindow/') -from helpwindowpresenter import HelpWindowPresenter -presenter = HelpWindowPresenter() -presenter.show_help_window() -)"; - boost::python::exec(pythonScript.c_str(), globals, globals); - } catch (boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Error launching Python Help Window."); - } -} - -void HelpWindow::launchPythonHelp() { - try { - boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); - boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); - - std::string currentPage = currentUrl.toStdString(); - boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), - mainNamespace); - } catch (const boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Failed to launch Python HelpWindow."); - } -} - -HelpWindow::HelpWindow(QWidget *parent) : QWidget(parent), currentUrl("about:blank") { - auto *layout = new QVBoxLayout(this); - - QPushButton *pythonHelpButton = new QPushButton("Python Implementation", this); - connect(pythonHelpButton, &QPushButton::clicked, this, &HelpWindow::launchPythonHelp); - layout->addWidget(pythonHelpButton); -} - -QString HelpWindow::currentPageUrl() const { - return this->currentUrl; // Provide the current URL -} - } // namespace MantidQt::API diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 066f77b713e0..9539bdcdf2dd 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -1,6 +1,8 @@ // Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + //---------------------------------- // Includes @@ -22,128 +24,188 @@ #include #include -#include +#include using namespace MantidQt::API; using Mantid::Kernel::AbstractInstantiator; using MantidQt::MantidWidgets::MantidHelpWindow; namespace { -// Static logger +// static logger Mantid::Kernel::Logger g_log("InterfaceManager"); // Load libraries once std::once_flag DLLS_LOADED; -// Track if the offline help message has been displayed +// Track if message saying offline help is unavailable has been shown bool offlineHelpMsgDisplayed = false; } // namespace -// Initialize HelpWindow factory +// initialise HelpWindow factory Mantid::Kernel::AbstractInstantiator *InterfaceManager::m_helpViewer = nullptr; //---------------------------------- // Public member functions //---------------------------------- +/** + * Return a specialized dialog for the given algorithm. If none exists then the + * default is returned + * @param alg :: A pointer to the algorithm + * @param parent :: An optional parent widget + * @param forScript :: A boolean indicating if this dialog is to be use for from + * a script or not. If true disables the autoexecution of the dialog + * @param presetValues :: A hash of property names to preset values for the + * dialog + * @param optionalMsg :: An optional message string to be placed at the top of + * the dialog + * @param enabled :: These properties will be left enabled + * @param disabled :: These properties will be left disabled + * @returns An AlgorithmDialog object + */ +AlgorithmDialog *InterfaceManager::createDialog(const std::shared_ptr &alg, QWidget *parent, + bool forScript, const QHash &presetValues, + const QString &optionalMsg, const QStringList &enabled, + const QStringList &disabled) { + AlgorithmDialog *dlg = nullptr; + if (AlgorithmDialogFactory::Instance().exists(alg->name() + "Dialog")) { + g_log.debug() << "Creating a specialised dialog for " << alg->name() << '\n'; + dlg = AlgorithmDialogFactory::Instance().createUnwrapped(alg->name() + "Dialog"); + } else { + dlg = new GenericDialog; + g_log.debug() << "No specialised dialog exists for the " << alg->name() + << " algorithm: a generic one has been created\n"; + } + + // The parent so that the dialog appears on top of it + dlg->setParent(parent); + dlg->setAttribute(Qt::WA_DeleteOnClose, true); + + // Set the QDialog window flags to ensure the dialog ends up on top + Qt::WindowFlags flags = Qt::WindowFlags(); +#ifdef Q_OS_MAC + // Work around to ensure that floating windows remain on top of the main + // application window, but below other applications on Mac + // Note: Qt::Tool cannot have both a max and min button on OSX + flags |= Qt::Tool; + flags |= Qt::CustomizeWindowHint; + flags |= Qt::WindowMinimizeButtonHint; + flags |= Qt::WindowCloseButtonHint; +#else + flags |= Qt::Dialog; + flags |= Qt::WindowCloseButtonHint; +#endif + dlg->setWindowFlags(flags); + + // Set the content + dlg->setAlgorithm(alg); + dlg->setPresetValues(presetValues); + dlg->isForScript(forScript); + dlg->setOptionalMessage(optionalMsg); + dlg->addEnabledAndDisableLists(enabled, disabled); + // Setup the layout + dlg->initializeLayout(); + + if (forScript) + dlg->executeOnAccept(false); // override default + return dlg; +} + +/** + * @param algorithmName :: Name of AlgorithmDialog + * @param version :: Version number + * @param parent :: An optional parent widget + * @param forScript :: A boolean indicating if this dialog is to be use for from + * a script or not + * @param presetValues :: A hash of property names to preset values for the + * dialog + * @param optionalMsg :: An optional message string to be placed at the top of + * the dialog + * @param enabled :: These properties will be left enabled + * @param disabled :: These properties will be left disabled + */ AlgorithmDialog *InterfaceManager::createDialogFromName(const QString &algorithmName, const int version, QWidget *parent, bool forScript, const QHash &presetValues, const QString &optionalMsg, const QStringList &enabled, const QStringList &disabled) { - auto alg = Mantid::API::AlgorithmManager::Instance().createUnmanaged(algorithmName.toStdString(), version); - if (!alg) { - g_log.error() << "Failed to create algorithm: " << algorithmName.toStdString() << "\n"; - return nullptr; - } - return createDialog(std::shared_ptr(alg), parent, forScript, presetValues, optionalMsg, - enabled, disabled); -} + // Create the algorithm. This should throw if the algorithm can't be found. + auto alg = Mantid::API::AlgorithmManager::Instance().create(algorithmName.toStdString(), version); -/** - * Show a help page using the default or Python-based HelpWindow - * @param url :: URL of the page to be displayed - */ -void InterfaceManager::showHelpPage(const QString &url) { - auto window = createHelpWindow(); - if (window) { - window->showPage(url); - } else { - launchPythonHelp(url); - } + // Forward call. + return createDialog(alg, parent, forScript, presetValues, optionalMsg, enabled, disabled); } /** - * Launch the Python-based HelpWindow - * @param url :: URL to pass to the Python HelpWindow + * Create a new instance of the correct type of UserSubWindow + * @param interface_name :: The registered name of the interface + * @param parent :: The parent widget + * @param isWindow :: Should the widget be an independent window */ -void InterfaceManager::launchPythonHelp(const QString &url) { +UserSubWindow *InterfaceManager::createSubWindow(const QString &interface_name, QWidget *parent, bool isWindow) { + UserSubWindow *user_win = nullptr; + std::string iname = interface_name.toStdString(); try { - boost::python::object mainNamespace = boost::python::import("__main__").attr("__dict__"); - boost::python::exec("from helpwindowpresenter import HelpPresenter", mainNamespace); + user_win = UserSubWindowFactory::Instance().createUnwrapped(iname); + } catch (Mantid::Kernel::Exception::NotFoundError &) { + user_win = nullptr; + } + if (user_win) { + g_log.debug() << "Created a specialised interface for " << iname << '\n'; - std::string currentPage = url.toStdString(); - boost::python::exec(("presenter = HelpPresenter.instance(); presenter.show_page('" + currentPage + "')").c_str(), - mainNamespace); + // set the parent. Note - setParent without flags parameter resets the flags + // i.e. window becomes a child widget + if (isWindow) { + user_win->setParent(parent, user_win->windowFlags()); + } else { + user_win->setParent(parent); + } - g_log.information("Launched Python-based HelpWindow."); - } catch (const boost::python::error_already_set &) { - PyErr_Print(); - g_log.error("Failed to launch Python HelpWindow."); - } -} + user_win->setInterfaceName(interface_name); + user_win->initializeLayout(); -void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { - auto window = createHelpWindow(); - if (window) { - window->showAlgorithm(name, version); - } else { - QString url = QString("file:///path/to/docs/algorithms/%1-v%2.html").arg(name).arg(version); - launchPythonHelp(url); - } -} + notifyExistingInterfaces(user_win); -void InterfaceManager::showConceptHelp(const QString &name) { - auto window = createHelpWindow(); - if (window) { - window->showConcept(name); } else { - QString url = QString("file:///path/to/docs/concepts/%1.html").arg(name); - launchPythonHelp(url); + g_log.error() << "Error creating interface " << iname << "\n"; } + return user_win; } -void InterfaceManager::showFitFunctionHelp(const QString &name) { - auto window = createHelpWindow(); - if (window) { - window->showFitFunction(name); - } else { - g_log.error("Fit function help is not implemented in the Python-based HelpWindow."); - } -} +/** + * Notifies the existing interfaces that a new interface has been created, and + * then notifies the new interface about the other interfaces which already + * exist. This can be used to connect signals between interfaces (override + * otherUserSubWindowCreated in the interface class). + * + * @param newWindow :: The interface just created + */ +void InterfaceManager::notifyExistingInterfaces(UserSubWindow *newWindow) { + auto &existingWindows = existingInterfaces(); -void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { - auto window = createHelpWindow(); - if (window) { - window->showCustomInterface(name, area, section); - } else { - QString url = QString("file:///path/to/docs/interfaces/%1/%2.html").arg(area).arg(name); - launchPythonHelp(url); - } + for (auto &window : existingWindows) + window->otherUserSubWindowCreated(newWindow); + + newWindow->otherUserSubWindowCreated(existingWindows); + + existingWindows.append(newWindow); } -void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } +QList> &InterfaceManager::existingInterfaces() { + static QList> existingSubWindows; + existingSubWindows.erase(std::remove_if(existingSubWindows.begin(), existingSubWindows.end(), + [](QPointer &window) { return window.isNull(); }), + existingSubWindows.end()); + return existingSubWindows; +} /** - * Closes the active HelpWindow, if any. + * The keys associated with UserSubWindow classes + * @returns A QStringList containing the keys from the InterfaceFactory that + * refer to UserSubWindow classes */ -void InterfaceManager::closeHelpWindow() { - if (MantidHelpWindow::helpWindowExists()) { - auto window = createHelpWindow(); - window->shutdown(); - } -} +QStringList InterfaceManager::getUserSubWindowKeys() const { return UserSubWindowFactory::Instance().keys(); } //---------------------------------- // Private member functions @@ -157,17 +219,10 @@ InterfaceManager::InterfaceManager() { /// Destructor InterfaceManager::~InterfaceManager() = default; -/** - * Register the HelpWindow factory - * @param factory :: The factory instance - */ void InterfaceManager::registerHelpWindowFactory(Mantid::Kernel::AbstractInstantiator *factory) { m_helpViewer = factory; } -/** - * Create an instance of the appropriate HelpWindow - */ MantidHelpInterface *InterfaceManager::createHelpWindow() const { if (m_helpViewer == nullptr) { if (!offlineHelpMsgDisplayed) { @@ -176,10 +231,118 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } return nullptr; } else { - auto *interface = m_helpViewer->createUnwrappedInstance(); + MantidHelpInterface *interface = this->m_helpViewer->createUnwrappedInstance(); if (!interface) { - g_log.error("Error creating help window."); + g_log.error("Error creating help window"); } return interface; } } + +void InterfaceManager::showHelpPage(const QString &url) { +#ifdef USE_PYTHON_WEB_HELP + // When using Python-based help: + // Here you would call a function that calls into Python to display the requested page. + // Placeholder: + // launchPythonHelpWindow(url.isEmpty() ? "index.html" : url); + launchPythonHelpWindow(url); +#else + // Original behavior + auto window = createHelpWindow(); + window->showPage(url); +#endif +} + +void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { +#ifdef USE_PYTHON_WEB_HELP + // Python-based version: construct the relative URL and call the Python help launcher + launchPythonHelpWindowForAlgorithm(name, version); +#else + // Original behavior + auto window = createHelpWindow(); + window->showAlgorithm(name, version); +#endif +} + +void InterfaceManager::showConceptHelp(const QString &name) { +#ifdef USE_PYTHON_WEB_HELP + launchPythonHelpWindowForConcept(name); +#else + // Original behavior + auto window = createHelpWindow(); + window->showConcept(name); +#endif +} + +void InterfaceManager::showFitFunctionHelp(const QString &name) { +#ifdef USE_PYTHON_WEB_HELP + launchPythonHelpWindowForFitFunction(name); +#else + // Original behavior + auto window = createHelpWindow(); + window->showFitFunction(name); +#endif +} + +void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { +#ifdef USE_PYTHON_WEB_HELP + launchPythonHelpWindowForCustomInterface(name, area, section); +#else + // Original behavior + auto window = createHelpWindow(); + window->showCustomInterface(name, area, section); +#endif +} + +void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } + +void InterfaceManager::closeHelpWindow() { +#ifdef USE_PYTHON_WEB_HELP + // If using Python-based help, implement closing the Python help window if needed. + // Placeholder: no operation here. +#else + // Original behavior + if (MantidHelpWindow::helpWindowExists()) { + auto window = createHelpWindow(); + window->shutdown(); + } +#endif +} + +#ifdef USE_PYTHON_WEB_HELP +// Placeholder implementations for the Python-based help window launching. +// In your real code, you would implement these using SIP/Boost.Python or similar +// to run the provided Python code that shows the QWebEngineView. + +void InterfaceManager::launchPythonHelpWindow(const QString &relativePage) { + g_log.information("Launching Python-based web help window with page: " + relativePage.toStdString()); + // TODO: Implement Python bridge call here +} + +void InterfaceManager::launchPythonHelpWindowForAlgorithm(const QString &name, int version) { + QString page = "algorithms/" + name; + if (version > 0) + page += "-v" + QString::number(version); + page += ".html"; + launchPythonHelpWindow(page); +} + +void InterfaceManager::launchPythonHelpWindowForConcept(const QString &name) { + QString pageName = name.isEmpty() ? "concepts/index.html" : "concepts/" + name + ".html"; + launchPythonHelpWindow(pageName); +} + +void InterfaceManager::launchPythonHelpWindowForFitFunction(const QString &name) { + QString pageName = name.isEmpty() ? "fitting/fitfunctions/index.html" : "fitting/fitfunctions/" + name + ".html"; + launchPythonHelpWindow(pageName); +} + +void InterfaceManager::launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, + const QString §ion) { + QString areaPath = area.isEmpty() ? "" : area + "/"; + QString base = "interfaces/" + areaPath + (name.isEmpty() ? "index.html" : name + ".html"); + if (!section.isEmpty()) + base += "#" + section; + launchPythonHelpWindow(base); +} +#endif diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index df22350e4b4e..32c04ab157ed 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -11,9 +11,7 @@ #include "MantidKernel/RegistrationHelper.h" #include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidDesktopServices.h" -#ifdef DOCS_QTHELP #include "MantidQtWidgets/Common/pqHelpWindow.h" -#endif #include #include #include @@ -45,10 +43,8 @@ namespace { Mantid::Kernel::Logger g_log("MantidHelpWindow"); } // namespace -#ifdef DOCS_QTHELP // initialise the help window QPointer MantidHelpWindow::g_helpWindow; -#endif /// name of the collection file itself const QString COLLECTION_FILE("MantidProject.qhc"); @@ -91,29 +87,17 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) g_log.debug("helpengine.setupData() returned false"); // create a new help window -#ifdef DOCS_QTHELP g_helpWindow = new pqHelpWindow(helpEngine, this, flags); g_helpWindow->setWindowTitle(QString("Mantid - Help")); g_helpWindow->setWindowIcon(QIcon(":/images/MantidIcon.ico")); -#else - throw std::runtime_error("TODO not implemented yet"); -#endif // show the home page on startup auto registeredDocs = helpEngine->registeredDocumentations(); if (registeredDocs.size() > 0) { -#ifdef DOCS_QTHELP g_helpWindow->showHomePage(registeredDocs[0]); -#else - throw std::runtime_error("TODO not implemented yet"); -#endif } -#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); -#else - throw std::runtime_error("TODO not implemented yet"); -#endif } else { g_log.information("Without collection file redirecting help to default web browser"); } @@ -123,15 +107,11 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) void MantidHelpWindow::showHelp(const QString &url) { g_log.debug() << "open help window for \"" << url.toStdString() << "\"\n"; // bring up the help window if it is showing -#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); if (!url.isEmpty()) { g_helpWindow->showPage(url); } -#else - throw std::runtime_error("TODO not implemented yet"); -#endif } void MantidHelpWindow::openWebpage(const QUrl &url) { @@ -303,12 +283,8 @@ void MantidHelpWindow::shutdown() { // Deleting the object ensures the help engine's destructor is called and // avoids a segfault when workbench is closed if (helpWindowExists()) { -#ifdef DOCS_QTHELP g_helpWindow->setAttribute(Qt::WA_DeleteOnClose); g_helpWindow->close(); -#else - throw std::runtime_error("TODO not implemented yet"); -#endif } else { g_log.warning("Something really wrong in MantidHelpWindow::shutdown()"); } diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp new file mode 100644 index 000000000000..7f1f9db84611 --- /dev/null +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -0,0 +1,27 @@ +#include "PythonHelpBridge.h" +#include +#include + +PythonHelpBridge::PythonHelpBridge() { + Py_Initialize(); // Initialize the Python interpreter + try { + boost::python::object main = boost::python::import("__main__"); + boost::python::object global = main.attr("__dict__"); + + // Import the helpwindowbridge module + boost::python::import("helpwindowbridge"); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + throw std::runtime_error("Failed to import 'helpwindowbridge' Python module."); + } +} + +void PythonHelpBridge::showHelpPage(const std::string &relative_url) { + try { + boost::python::object module = boost::python::import("helpwindowbridge"); + module.attr("show_help_page")(relative_url); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + throw std::runtime_error("Error calling show_help_page in Python."); + } +} diff --git a/qt/widgets/common/src/SelectFunctionDialog.cpp b/qt/widgets/common/src/SelectFunctionDialog.cpp index 465cd07464a0..a460f70115ff 100644 --- a/qt/widgets/common/src/SelectFunctionDialog.cpp +++ b/qt/widgets/common/src/SelectFunctionDialog.cpp @@ -250,7 +250,7 @@ void SelectFunctionDialog::helpClicked() const { if (!function.isEmpty()) { MantidQt::API::HelpWindow::showFitFunction(function.toStdString()); } else { // No function selected open fit function index - MantidQt::API::HelpWindow::showFitFunction(QStringLiteral("")); + MantidQt::API::HelpWindow::showFitFunction(""); } } diff --git a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h index c79091d01013..30208515bf8e 100644 --- a/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h +++ b/qt/widgets/mplcpp/inc/MantidQtWidgets/MplCpp/Colormap.h @@ -11,11 +11,7 @@ #undef slots #include "MantidQtWidgets/Common/Python/Object.h" #pragma pop_macro("slots") -#include #include -#include -#include -#include namespace MantidQt { namespace Widgets { From 4d17218b05a8c684a5fcdee4b6e36fdb412bb97c Mon Sep 17 00:00:00 2001 From: darshdinger Date: Mon, 16 Dec 2024 08:59:57 -0500 Subject: [PATCH 07/28] Smal fixes --- qt/widgets/common/src/InterfaceManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 9539bdcdf2dd..1f0d8d574d01 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -24,7 +24,7 @@ #include #include -#include +#include using namespace MantidQt::API; using Mantid::Kernel::AbstractInstantiator; From 18e49918e706c3c454a144946f7744d0d452062b Mon Sep 17 00:00:00 2001 From: darshdinger Date: Mon, 16 Dec 2024 09:31:18 -0500 Subject: [PATCH 08/28] Final updates --- .../widgets/helpwindow/helpwindowbridge.py | 24 +++++++++++++++++-- .../widgets/helpwindow/helpwindowview.py | 15 +++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py index 255576ff8d13..d8525f57a607 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py @@ -1,8 +1,15 @@ +import os from mantidqt.widgets.helpwindow.helpwindowpresenter import HelpWindowPresenter from qtpy.QtCore import QUrl _presenter = None +online_base_url = "https://docs.mantidproject.org/" +# NOTE: Once you build the html docs using the command ninja docs-html, you will need to +# use the command export MANTID_LOCAL_DOCS_BASE="/path/to/build/docs/html". +# If this it not set, this will default to the online docs. +local_docs_base = os.environ.get("MANTID_LOCAL_DOCS_BASE") # e.g. /path/to/build/docs/html + def show_help_page(relative_url): """ @@ -11,6 +18,19 @@ def show_help_page(relative_url): global _presenter if _presenter is None: _presenter = HelpWindowPresenter() - full_url = "https://docs.mantidproject.org/" + relative_url - _presenter.view.browser.setUrl(QUrl(full_url)) + + # Default to index.html if no specific file given + if not relative_url or not relative_url.endswith(".html"): + relative_url = "index.html" + + if local_docs_base and os.path.isdir(local_docs_base): + # Use local docs + full_path = os.path.join(local_docs_base, relative_url) + file_url = QUrl.fromLocalFile(full_path) + _presenter.view.browser.setUrl(file_url) + else: + # Use online docs + full_url = online_base_url + relative_url + _presenter.view.browser.setUrl(QUrl(full_url)) + _presenter.show_help_window() diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py index 626e281b3ef9..ab86e552ccc0 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -1,5 +1,7 @@ +import os from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QWidget from qtpy.QtWebEngineWidgets import QWebEngineView +from qtpy.QtCore import QUrl class HelpWindowView(QMainWindow): @@ -9,11 +11,18 @@ def __init__(self, presenter): self.setWindowTitle("Python Help Window") self.resize(800, 600) - # Web view to display the help documentation self.browser = QWebEngineView() - self.browser.setUrl("https://docs.mantidproject.org/") - # Layout + # Determine initial URL: + local_docs_base = os.environ.get("MANTID_LOCAL_DOCS_BASE") + if local_docs_base and os.path.isdir(local_docs_base): + # Use local docs if available + index_path = os.path.join(local_docs_base, "index.html") + self.browser.setUrl(QUrl.fromLocalFile(index_path)) + else: + # Fallback to online docs + self.browser.setUrl(QUrl("https://docs.mantidproject.org/")) + layout = QVBoxLayout() layout.addWidget(self.browser) container = QWidget() From 432bda5ec4ced95cb9c05f8b241742c476d2e8d9 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Tue, 17 Dec 2024 13:26:30 -0500 Subject: [PATCH 09/28] More updates and Pete's changes --- .../CMake/CppCheck_Suppressions.txt.in | 11 --- qt/widgets/common/CMakeLists.txt | 16 +++- .../inc/MantidQtWidgets/Common/HelpWindow.h | 1 - .../MantidQtWidgets/Common/InterfaceManager.h | 7 +- .../MantidQtWidgets/Common/MantidHelpWindow.h | 20 +++-- .../MantidQtWidgets/Common/PythonHelpWindow.h | 30 +++++++ qt/widgets/common/src/InterfaceManager.cpp | 66 +++++++------- qt/widgets/common/src/MantidHelpWindow.cpp | 59 +++++++++--- qt/widgets/common/src/PythonHelpBridge.cpp | 4 +- qt/widgets/common/src/PythonHelpWindow.cpp | 90 +++++++++++++++++++ 10 files changed, 227 insertions(+), 77 deletions(-) create mode 100644 qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h create mode 100644 qt/widgets/common/src/PythonHelpWindow.cpp diff --git a/buildconfig/CMake/CppCheck_Suppressions.txt.in b/buildconfig/CMake/CppCheck_Suppressions.txt.in index 985876043828..8f80c7f33cd5 100644 --- a/buildconfig/CMake/CppCheck_Suppressions.txt.in +++ b/buildconfig/CMake/CppCheck_Suppressions.txt.in @@ -1157,17 +1157,6 @@ constVariableReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/InstrumentSelec constVariableReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/ListPropertyWidget.cpp:46 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/FitDomain.h:35 virtualCallInConstructor:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/ManageUserDirectories.h:39 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:318 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:320 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:329 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:331 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:342 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:343 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:344 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:354 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:355 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:356 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:357 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/Message.h:52 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/Message.h:56 constParameterReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:301 diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index aa755347bbcc..1091247cacfa 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -80,7 +80,6 @@ set(SRC_FILES src/ParseKeyValueString.cpp src/pixmaps.cpp src/PluginLibraries.cpp - src/pqHelpWindow.cxx src/ProcessingAlgoWidget.cpp src/ProgressableView.cpp src/PropertyHandler.cpp @@ -158,6 +157,9 @@ set(SRC_FILES src/Python/Sip.cpp src/Python/QHashToDict.cpp ) +if(DOCS_QTHELP) + list(APPEND SRC_FILES src/pqHelpWindow.cxx) +endif() set(QT5_MOC_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.h inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.h @@ -346,6 +348,9 @@ set(QT5_INC_FILES inc/MantidQtWidgets/Common/Python/Object.h inc/MantidQtWidgets/Common/Python/QHashToDict.h ) +if(DOCS_QTHELP) + list(APPEND QT5_INC_FILES inc/MantidQtWidgets/Common/pqHelpWindow.h) +endif() set(QT5_UI_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.ui inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.ui @@ -357,7 +362,6 @@ set(QT5_UI_FILES inc/MantidQtWidgets/Common/MuonPeriodInfo.ui inc/MantidQtWidgets/Common/FileFinderWidget.ui inc/MantidQtWidgets/Common/FitScriptGenerator.ui - inc/MantidQtWidgets/Common/pqHelpWindow.ui inc/MantidQtWidgets/Common/ProcessingAlgoWidget.ui inc/MantidQtWidgets/Common/RenameParDialog.ui inc/MantidQtWidgets/Common/ScriptRepositoryView.ui @@ -366,6 +370,9 @@ set(QT5_UI_FILES inc/MantidQtWidgets/Common/SlitCalculator.ui inc/MantidQtWidgets/Common/UserFunctionDialog.ui ) +if(DOCS_QTHELP) + list(APPEND QT5_UI_FILES inc/MantidQtWidgets/Common/pqHelpWindow.ui) +endif() set(MOC_FILES inc/MantidQtWidgets/Common/AlgorithmDialog.h inc/MantidQtWidgets/Common/AlgorithmHistoryWindow.h @@ -431,7 +438,6 @@ set(MOC_FILES inc/MantidQtWidgets/Common/MuonFitPropertyBrowser.h inc/MantidQtWidgets/Common/MuonFunctionBrowser.h inc/MantidQtWidgets/Common/MuonPeriodInfo.h - inc/MantidQtWidgets/Common/pqHelpWindow.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h @@ -621,8 +627,10 @@ set(UI_FILES inc/MantidQtWidgets/Common/SlicingAlgorithmDialog.ui inc/MantidQtWidgets/Common/SlitCalculator.ui inc/MantidQtWidgets/Common/UserFunctionDialog.ui - inc/MantidQtWidgets/Common/pqHelpWindow.ui ) +if(DOCS_QTHELP) + list(APPEND UI_FILES inc/MantidQtWidgets/Common/pqHelpWindow.ui) +endif() set(TARGET_LIBRARIES ${CORE_MANTIDLIBS} ${POCO_LIBRARIES} ${Boost_LIBRARIES}) if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(APPEND TARGET_LIBRARIES "-framework CoreFoundation") diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h index 8ce46c921f62..22904045d8be 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/HelpWindow.h @@ -1,4 +1,3 @@ - // Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2013 ISIS Rutherford Appleton Laboratory UKRI, diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index ff2ca5e6e131..333f7f499e66 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -123,13 +123,12 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { virtual ~InterfaceManager(); private: + void notifyExistingInterfaces(UserSubWindow *newWindow); + /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; - void notifyExistingInterfaces(UserSubWindow *newWindow); - -#ifdef USE_PYTHON_WEB_HELP - // Placeholder function that you would implement to run the Python-based help window +#ifndef DOCS_QTHELP void launchPythonHelpWindow(const QString &relativePage); void launchPythonHelpWindowForAlgorithm(const QString &name, int version = -1); void launchPythonHelpWindowForConcept(const QString &name); diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h index 1d503ff3dddb..84136b8e7ecc 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h @@ -16,8 +16,9 @@ class QHelpEngine; class QString; class QWidget; +#ifdef DOCS_QTHELP class pqHelpWindow; - +#endif namespace MantidQt { namespace MantidWidgets { @@ -25,7 +26,7 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf Q_OBJECT public: - static bool helpWindowExists() { return !g_helpWindow.isNull(); } + static bool helpWindowExists(); MantidHelpWindow(const Qt::WindowFlags &flags = Qt::WindowFlags()); @@ -43,25 +44,26 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf void showCustomInterface(const QString &name, const QString &area = QString(), const QString §ion = QString()) override; +public slots: + /// Perform any clean up on main window shutdown + void shutdown() override; + void warning(const QString &msg); + private: void showHelp(const QString &url); void openWebpage(const QUrl &url); /// The full path of the collection file. std::string m_collectionFile; +#ifdef DOCS_QTHELP /// The window that renders the help information static QPointer g_helpWindow; - +#endif /// Whether this is the very first startup of the helpwindow. bool m_firstRun; - void findCollectionFile(std::string &binDir); + void findCollectionFile(const std::string &binDir); void determineFileLocs(); - -public slots: - /// Perform any clean up on main window shutdown - void shutdown() override; - void warning(const QString &msg); }; } // namespace MantidWidgets diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h new file mode 100644 index 000000000000..bddf6aee6773 --- /dev/null +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h @@ -0,0 +1,30 @@ +#pragma once +#include "MantidQtWidgets/Common/MantidHelpInterface.h" +#include +#include +#include + +namespace MantidQt { +namespace MantidWidgets { + +class PythonHelpWindow : public MantidQt::API::MantidHelpInterface { +public: + PythonHelpWindow(); + void showPage(const std::string &url = std::string()) override; + void showPage(const QString &url) override; + void showPage(const QUrl &url) override; + void showAlgorithm(const std::string &name = std::string(), const int version = -1) override; + void showAlgorithm(const QString &name, const int version = -1) override; + void showConcept(const std::string &name) override; + void showConcept(const QString &name) override; + void showFitFunction(const std::string &name = std::string()) override; + void showFitFunction(const QString &name) override; + void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), + const std::string §ion = std::string()) override; + void showCustomInterface(const QString &name, const QString &area = QString(), + const QString §ion = QString()) override; + void shutdown() override; +}; + +} // namespace MantidWidgets +} // namespace MantidQt diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 1f0d8d574d01..ed79a53b3ef5 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -240,101 +240,101 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } void InterfaceManager::showHelpPage(const QString &url) { -#ifdef USE_PYTHON_WEB_HELP - // When using Python-based help: - // Here you would call a function that calls into Python to display the requested page. - // Placeholder: - // launchPythonHelpWindow(url.isEmpty() ? "index.html" : url); - launchPythonHelpWindow(url); -#else +#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showPage(url); +#else + launchPythonHelpWindow(url.isEmpty() ? "index.html" : url); + #endif } void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { -#ifdef USE_PYTHON_WEB_HELP - // Python-based version: construct the relative URL and call the Python help launcher - launchPythonHelpWindowForAlgorithm(name, version); -#else +#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showAlgorithm(name, version); +#else + // Python-based version: construct the relative URL and call the Python help launcher + launchPythonHelpWindowForAlgorithm(name, version); + #endif } void InterfaceManager::showConceptHelp(const QString &name) { -#ifdef USE_PYTHON_WEB_HELP - launchPythonHelpWindowForConcept(name); -#else +#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showConcept(name); +#else + launchPythonHelpWindowForConcept(name); #endif } void InterfaceManager::showFitFunctionHelp(const QString &name) { -#ifdef USE_PYTHON_WEB_HELP - launchPythonHelpWindowForFitFunction(name); -#else +#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showFitFunction(name); +#else + launchPythonHelpWindowForFitFunction(name); #endif } void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { -#ifdef USE_PYTHON_WEB_HELP - launchPythonHelpWindowForCustomInterface(name, area, section); -#else +#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showCustomInterface(name, area, section); +#else + launchPythonHelpWindowForCustomInterface(name, area, section); #endif } void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } void InterfaceManager::closeHelpWindow() { -#ifdef USE_PYTHON_WEB_HELP - // If using Python-based help, implement closing the Python help window if needed. - // Placeholder: no operation here. -#else +#ifdef DOCS_QTHELP // Original behavior if (MantidHelpWindow::helpWindowExists()) { auto window = createHelpWindow(); window->shutdown(); } +#elses + // If using Python-based help, implement closing the Python help window if needed. + // Placeholder: no operation here. #endif } -#ifdef USE_PYTHON_WEB_HELP +#ifndef DOCS_QTHELP +#include "MantidQtWidgets/Common/PythonHelpBridge.h" // Placeholder implementations for the Python-based help window launching. // In your real code, you would implement these using SIP/Boost.Python or similar // to run the provided Python code that shows the QWebEngineView. void InterfaceManager::launchPythonHelpWindow(const QString &relativePage) { - g_log.information("Launching Python-based web help window with page: " + relativePage.toStdString()); - // TODO: Implement Python bridge call here + static PythonHelpBridge bridge; + bridge.showHelpPage(relativePage.toStdString()); } void InterfaceManager::launchPythonHelpWindowForAlgorithm(const QString &name, int version) { QString page = "algorithms/" + name; if (version > 0) - page += "-v" + QString::number(version); - page += ".html"; + page += "-v" + QString::number(version) + ".html"; + else + page += ".html"; launchPythonHelpWindow(page); } void InterfaceManager::launchPythonHelpWindowForConcept(const QString &name) { - QString pageName = name.isEmpty() ? "concepts/index.html" : "concepts/" + name + ".html"; - launchPythonHelpWindow(pageName); + QString page = name.isEmpty() ? "concepts/index.html" : "concepts/" + name + ".html"; + launchPythonHelpWindow(page); } void InterfaceManager::launchPythonHelpWindowForFitFunction(const QString &name) { - QString pageName = name.isEmpty() ? "fitting/fitfunctions/index.html" : "fitting/fitfunctions/" + name + ".html"; - launchPythonHelpWindow(pageName); + QString page = name.isEmpty() ? "fitting/fitfunctions/index.html" : "fitting/fitfunctions/" + name + ".html"; + launchPythonHelpWindow(page); } void InterfaceManager::launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index 32c04ab157ed..da8c056309cc 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -7,11 +7,14 @@ #include "MantidQtWidgets/Common/MantidHelpWindow.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidKernel/ConfigService.h" +#include "MantidKernel/Exception.h" #include "MantidKernel/Logger.h" #include "MantidKernel/RegistrationHelper.h" #include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidDesktopServices.h" +#ifdef DOCS_QTHELP #include "MantidQtWidgets/Common/pqHelpWindow.h" +#endif #include #include #include @@ -35,6 +38,7 @@ namespace MantidQt::MantidWidgets { using std::string; using namespace MantidQt::API; +using Mantid::Kernel::Exception::NotImplementedError; REGISTER_HELPWINDOW(MantidHelpWindow) @@ -43,8 +47,10 @@ namespace { Mantid::Kernel::Logger g_log("MantidHelpWindow"); } // namespace +#ifdef DOCS_QTHELP // initialise the help window QPointer MantidHelpWindow::g_helpWindow; +#endif /// name of the collection file itself const QString COLLECTION_FILE("MantidProject.qhc"); @@ -63,6 +69,14 @@ const QString HTML_BASE_PATH("/"); /// Page to display if nothing provided const QString DEFAULT_PAGENAME("index"); +bool MantidHelpWindow::helpWindowExists() { +#ifdef DOCS_QTHELP + return !g_helpWindow.isNull(); +#else + throw NotImplementedError("This needs to be implemented"); +#endif +} + /** * Default constructor shows the base index page. */ @@ -87,17 +101,30 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) g_log.debug("helpengine.setupData() returned false"); // create a new help window +#ifdef DOCS_QTHELP g_helpWindow = new pqHelpWindow(helpEngine, this, flags); g_helpWindow->setWindowTitle(QString("Mantid - Help")); g_helpWindow->setWindowIcon(QIcon(":/images/MantidIcon.ico")); +#else + UNUSED_ARG(flags); + throw NotImplementedError("This needs to be implemented"); +#endif // show the home page on startup auto registeredDocs = helpEngine->registeredDocumentations(); if (registeredDocs.size() > 0) { +#ifdef DOCS_QTHELP g_helpWindow->showHomePage(registeredDocs[0]); +#else + throw NotImplementedError("This needs to be implemented"); +#endif } +#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); +#else + throw NotImplementedError("This needs to be implemented"); +#endif } else { g_log.information("Without collection file redirecting help to default web browser"); } @@ -107,11 +134,15 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) void MantidHelpWindow::showHelp(const QString &url) { g_log.debug() << "open help window for \"" << url.toStdString() << "\"\n"; // bring up the help window if it is showing +#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); if (!url.isEmpty()) { g_helpWindow->showPage(url); } +#else + throw NotImplementedError("This needs to be implemented"); +#endif } void MantidHelpWindow::openWebpage(const QUrl &url) { @@ -283,8 +314,12 @@ void MantidHelpWindow::shutdown() { // Deleting the object ensures the help engine's destructor is called and // avoids a segfault when workbench is closed if (helpWindowExists()) { +#ifdef DOCS_QTHELP g_helpWindow->setAttribute(Qt::WA_DeleteOnClose); g_helpWindow->close(); +#else + throw NotImplementedError("This needs to be implemented"); +#endif } else { g_log.warning("Something really wrong in MantidHelpWindow::shutdown()"); } @@ -298,7 +333,7 @@ void MantidHelpWindow::shutdown() { * * @param binDir The location of the mantid executable. */ -void MantidHelpWindow::findCollectionFile(std::string &binDir) { +void MantidHelpWindow::findCollectionFile(const std::string &binDir) { // this being empty notes the feature being disabled m_collectionFile = ""; @@ -315,9 +350,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } // try where the builds will put it for a single configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -326,9 +361,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } } // try where the builds will put it for a multi-configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -339,9 +374,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try in windows/linux install location searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -351,10 +386,10 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try a special place for mac/osx searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp index 7f1f9db84611..412b23481bee 100644 --- a/qt/widgets/common/src/PythonHelpBridge.cpp +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -3,12 +3,10 @@ #include PythonHelpBridge::PythonHelpBridge() { - Py_Initialize(); // Initialize the Python interpreter + Py_Initialize(); try { boost::python::object main = boost::python::import("__main__"); boost::python::object global = main.attr("__dict__"); - - // Import the helpwindowbridge module boost::python::import("helpwindowbridge"); } catch (boost::python::error_already_set &) { PyErr_Print(); diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp new file mode 100644 index 000000000000..53e0c4265d95 --- /dev/null +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -0,0 +1,90 @@ +#include "MantidQtWidgets/Common/PythonHelpWindow.h" +#include "MantidQtWidgets/Common/PythonHelpBridge.h" +#include +#include + +namespace MantidQt { +namespace MantidWidgets { + +#ifndef DOCS_QTHELP +REGISTER_HELPWINDOW(PythonHelpWindow) +#endif + +PythonHelpWindow::PythonHelpWindow() : MantidQt::API::MantidHelpInterface() {} + +void PythonHelpWindow::showPage(const std::string &url) { + PythonHelpBridge bridge; + bridge.showHelpPage(url.empty() ? "index.html" : url); +} + +void PythonHelpWindow::showPage(const QString &url) { + PythonHelpBridge bridge; + std::string page = url.isEmpty() ? "index.html" : url.toStdString(); + bridge.showHelpPage(page); +} + +void PythonHelpWindow::showPage(const QUrl &url) { + PythonHelpBridge bridge; + std::string page = url.isEmpty() ? "index.html" : url.toString().toStdString(); + bridge.showHelpPage(page); +} + +void PythonHelpWindow::showAlgorithm(const std::string &name, const int version) { + QString page = "algorithms/" + QString::fromStdString(name); + if (!name.empty() && version > 0) + page += "-v" + QString::number(version) + ".html"; + else if (!name.empty()) + page += ".html"; + else + page = "algorithms/index.html"; + showPage(page); +} + +void PythonHelpWindow::showAlgorithm(const QString &name, const int version) { + std::string n = name.toStdString(); + showAlgorithm(n, version); +} + +void PythonHelpWindow::showConcept(const std::string &name) { + QString page = name.empty() ? "concepts/index.html" : "concepts/" + QString::fromStdString(name) + ".html"; + showPage(page); +} + +void PythonHelpWindow::showConcept(const QString &name) { + std::string n = name.toStdString(); + showConcept(n); +} + +void PythonHelpWindow::showFitFunction(const std::string &name) { + QString page = name.empty() ? "fitting/fitfunctions/index.html" + : "fitting/fitfunctions/" + QString::fromStdString(name) + ".html"; + showPage(page); +} + +void PythonHelpWindow::showFitFunction(const QString &name) { + std::string n = name.toStdString(); + showFitFunction(n); +} + +void PythonHelpWindow::showCustomInterface(const std::string &name, const std::string &area, + const std::string §ion) { + QString areaPath = area.empty() ? "" : QString::fromStdString(area) + "/"; + QString page = "interfaces/" + areaPath + (name.empty() ? "index.html" : QString::fromStdString(name) + ".html"); + if (!section.empty()) + page += "#" + QString::fromStdString(section); + showPage(page); +} + +void PythonHelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { + std::string n = name.toStdString(); + std::string a = area.toStdString(); + std::string s = section.toStdString(); + showCustomInterface(n, a, s); +} + +void PythonHelpWindow::shutdown() { + // no-op for python help window +} + +} // namespace MantidWidgets +} // namespace MantidQt From 35b39bb513e7a0bef32031373b9964fc79288639 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Tue, 17 Dec 2024 15:45:59 -0500 Subject: [PATCH 10/28] Revert some of Petes changes and some more updates --- qt/widgets/common/CMakeLists.txt | 40 +++++----- .../MantidQtWidgets/Common/InterfaceManager.h | 2 - .../MantidQtWidgets/Common/PythonHelpWindow.h | 2 + qt/widgets/common/src/InterfaceManager.cpp | 76 ++++++------------- qt/widgets/common/src/MantidHelpWindow.cpp | 61 ++++----------- 5 files changed, 62 insertions(+), 119 deletions(-) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 1091247cacfa..3778cd841eb5 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -80,11 +80,14 @@ set(SRC_FILES src/ParseKeyValueString.cpp src/pixmaps.cpp src/PluginLibraries.cpp + src/pqHelpWindow.cxx src/ProcessingAlgoWidget.cpp src/ProgressableView.cpp src/PropertyHandler.cpp src/PropertyWidget.cpp src/PropertyWidgetFactory.cpp + src/PythonHelpBridge.cpp + src/PythonHelpWindow.cpp src/PythonRunner.cpp src/QtAlgorithmRunner.cpp src/QtJobRunner.cpp @@ -157,9 +160,7 @@ set(SRC_FILES src/Python/Sip.cpp src/Python/QHashToDict.cpp ) -if(DOCS_QTHELP) - list(APPEND SRC_FILES src/pqHelpWindow.cxx) -endif() + set(QT5_MOC_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.h inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.h @@ -216,6 +217,8 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/PropertyWidget.h + inc/MantidQtWidgets/Common/PythonBridge.h + inc/MantidQtWidgets/Common/PythonHelpWindow.h inc/MantidQtWidgets/Common/PythonRunner.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h inc/MantidQtWidgets/Common/QtJobRunner.h @@ -262,6 +265,7 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h inc/MantidQtWidgets/Common/QtPropertyBrowser/WorkspaceEditorFactory.h ) + # Include files aren't required, but this makes them appear in Visual Studio set(QT5_INC_FILES ${QT5_MOC_FILES} @@ -348,9 +352,7 @@ set(QT5_INC_FILES inc/MantidQtWidgets/Common/Python/Object.h inc/MantidQtWidgets/Common/Python/QHashToDict.h ) -if(DOCS_QTHELP) - list(APPEND QT5_INC_FILES inc/MantidQtWidgets/Common/pqHelpWindow.h) -endif() + set(QT5_UI_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.ui inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.ui @@ -362,6 +364,7 @@ set(QT5_UI_FILES inc/MantidQtWidgets/Common/MuonPeriodInfo.ui inc/MantidQtWidgets/Common/FileFinderWidget.ui inc/MantidQtWidgets/Common/FitScriptGenerator.ui + inc/MantidQtWidgets/Common/pqHelpWindow.ui inc/MantidQtWidgets/Common/ProcessingAlgoWidget.ui inc/MantidQtWidgets/Common/RenameParDialog.ui inc/MantidQtWidgets/Common/ScriptRepositoryView.ui @@ -370,9 +373,7 @@ set(QT5_UI_FILES inc/MantidQtWidgets/Common/SlitCalculator.ui inc/MantidQtWidgets/Common/UserFunctionDialog.ui ) -if(DOCS_QTHELP) - list(APPEND QT5_UI_FILES inc/MantidQtWidgets/Common/pqHelpWindow.ui) -endif() + set(MOC_FILES inc/MantidQtWidgets/Common/AlgorithmDialog.h inc/MantidQtWidgets/Common/AlgorithmHistoryWindow.h @@ -438,6 +439,7 @@ set(MOC_FILES inc/MantidQtWidgets/Common/MuonFitPropertyBrowser.h inc/MantidQtWidgets/Common/MuonFunctionBrowser.h inc/MantidQtWidgets/Common/MuonPeriodInfo.h + inc/MantidQtWidgets/Common/pqHelpWindow.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h @@ -478,6 +480,7 @@ set(MOC_FILES inc/MantidQtWidgets/Common/QtPropertyBrowser/qtbuttonpropertybrowser.h inc/MantidQtWidgets/Common/QtPropertyBrowser/qtgroupboxpropertybrowser.h ) + # Include files aren't required, but this makes them appear in Visual Studio set(INC_FILES ${MOC_FILES} @@ -605,6 +608,7 @@ set(INC_FILES inc/MantidQtWidgets/Common/Batch/MockJobTreeView.h inc/MantidQtWidgets/Common/Python/Object.h ) + set(UI_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.ui inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.ui @@ -627,14 +631,15 @@ set(UI_FILES inc/MantidQtWidgets/Common/SlicingAlgorithmDialog.ui inc/MantidQtWidgets/Common/SlitCalculator.ui inc/MantidQtWidgets/Common/UserFunctionDialog.ui + inc/MantidQtWidgets/Common/pqHelpWindow.ui ) -if(DOCS_QTHELP) - list(APPEND UI_FILES inc/MantidQtWidgets/Common/pqHelpWindow.ui) -endif() + set(TARGET_LIBRARIES ${CORE_MANTIDLIBS} ${POCO_LIBRARIES} ${Boost_LIBRARIES}) + if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") list(APPEND TARGET_LIBRARIES "-framework CoreFoundation") endif() + # Target Additional components for this module find_package( Qt5 ${QT_MIN_VERSION} @@ -663,6 +668,7 @@ else() message(FATAL_ERROR "Unable to find suitable module for web widgets. Tried: WebEnginewidgets, WebKitWidgets") endif() endif() + # If not sip header is defined we need to generate one with sip-module if(SIP_INCLUDE_DIR AND EXISTS ${SIP_INCLUDE_DIR}/sip.h) set(_sip_include_dir ${SIP_INCLUDE_DIR}) @@ -676,6 +682,7 @@ else() COMMENT "Generating sip.h for common widgets target" ) endif() + mtd_add_qt_library( TARGET_NAME MantidQtWidgetsCommon QT_VERSION 5 @@ -694,11 +701,6 @@ mtd_add_qt_library( OSX_INSTALL_RPATH @loader_path/../MacOS @loader_path/../Frameworks LINUX_INSTALL_RPATH "\$ORIGIN/../${WORKBENCH_LIB_DIR}" ) -# add an extra define to use pqhelpwindow which wraps qtassistant -if(DOCS_QTHELP) - # warning - this is assuming that the output is qt5 only - target_compile_definitions(MantidQtWidgetsCommonQt5 PUBLIC -DDOCS_QTHELP) -endif() set(TEST_FILES test/AlgorithmHintStrategyTest.h @@ -736,7 +738,9 @@ set(TEST_FILES test/WorkspacePresenter/ADSAdapterTest.h test/WorkspacePresenter/WorkspacePresenterTest.h ) + set(CXXTEST_EXTRA_HEADER_INCLUDE ${CMAKE_CURRENT_LIST_DIR}/test/WidgetsCommonTestInitialization.h) + set(QT5_TEST_FILES test/AlgorithmRunnerTest.h test/BatchAlgorithmRunnerTest.h @@ -775,6 +779,7 @@ set(QT5_TEST_FILES test/WorkspacePresenter/ADSAdapterTest.h test/WorkspacePresenter/WorkspacePresenterTest.h ) + if(MANTID_FRAMEWORK_LIB STREQUAL "BUILD") mtd_add_qt_tests( TARGET_NAME MantidQtWidgetsCommonTest @@ -791,6 +796,7 @@ if(MANTID_FRAMEWORK_LIB STREQUAL "BUILD") MTD_QT_LINK_LIBS MantidQtWidgetsCommon PARENT_DEPENDENCIES GUITests ) + add_framework_test_helpers(MantidQtWidgetsCommonTestQt5) pyunittest_add_test(${CMAKE_CURRENT_SOURCE_DIR} MantidQtWidgetsCommonPyTest ${TEST_PY_FILES}) endif() diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index 333f7f499e66..2dbb47c4f026 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -128,13 +128,11 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; -#ifndef DOCS_QTHELP void launchPythonHelpWindow(const QString &relativePage); void launchPythonHelpWindowForAlgorithm(const QString &name, int version = -1); void launchPythonHelpWindowForConcept(const QString &name); void launchPythonHelpWindowForFitFunction(const QString &name); void launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, const QString §ion); -#endif }; } // namespace API diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h index bddf6aee6773..c0bdf6db28ba 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h @@ -1,4 +1,6 @@ #pragma once + +#include "DllOption.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" #include #include diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index ed79a53b3ef5..244ab11f0230 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -14,6 +14,7 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpWindow.h" #include "MantidQtWidgets/Common/PluginLibraries.h" +#include "MantidQtWidgets/Common/PythonHelpBridge.h" #include "MantidQtWidgets/Common/UserSubWindow.h" #include "MantidQtWidgets/Common/UserSubWindowFactory.h" @@ -240,90 +241,60 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } void InterfaceManager::showHelpPage(const QString &url) { -#ifdef DOCS_QTHELP // Original behavior auto window = createHelpWindow(); window->showPage(url); -#else - launchPythonHelpWindow(url.isEmpty() ? "index.html" : url); - -#endif } void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { -#ifdef DOCS_QTHELP - // Original behavior auto window = createHelpWindow(); - window->showAlgorithm(name, version); -#else - // Python-based version: construct the relative URL and call the Python help launcher - launchPythonHelpWindowForAlgorithm(name, version); - -#endif + if (window) + window->showAlgorithm(name, version); + else + launchPythonHelpWindowForAlgorithm(name, version); } void InterfaceManager::showConceptHelp(const QString &name) { -#ifdef DOCS_QTHELP - // Original behavior auto window = createHelpWindow(); - window->showConcept(name); -#else - launchPythonHelpWindowForConcept(name); -#endif + if (window) + window->showConcept(name); + else + launchPythonHelpWindowForConcept(name); } void InterfaceManager::showFitFunctionHelp(const QString &name) { -#ifdef DOCS_QTHELP - // Original behavior auto window = createHelpWindow(); - window->showFitFunction(name); -#else - launchPythonHelpWindowForFitFunction(name); -#endif + if (window) + window->showFitFunction(name); + else + launchPythonHelpWindowForFitFunction(name); } void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { -#ifdef DOCS_QTHELP - // Original behavior auto window = createHelpWindow(); - window->showCustomInterface(name, area, section); -#else - launchPythonHelpWindowForCustomInterface(name, area, section); -#endif + if (window) + window->showCustomInterface(name, area, section); + else + launchPythonHelpWindowForCustomInterface(name, area, section); } void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } void InterfaceManager::closeHelpWindow() { -#ifdef DOCS_QTHELP - // Original behavior if (MantidHelpWindow::helpWindowExists()) { auto window = createHelpWindow(); - window->shutdown(); + if (window) + window->shutdown(); } -#elses - // If using Python-based help, implement closing the Python help window if needed. - // Placeholder: no operation here. -#endif } -#ifndef DOCS_QTHELP -#include "MantidQtWidgets/Common/PythonHelpBridge.h" -// Placeholder implementations for the Python-based help window launching. -// In your real code, you would implement these using SIP/Boost.Python or similar -// to run the provided Python code that shows the QWebEngineView. - void InterfaceManager::launchPythonHelpWindow(const QString &relativePage) { static PythonHelpBridge bridge; bridge.showHelpPage(relativePage.toStdString()); } void InterfaceManager::launchPythonHelpWindowForAlgorithm(const QString &name, int version) { - QString page = "algorithms/" + name; - if (version > 0) - page += "-v" + QString::number(version) + ".html"; - else - page += ".html"; + QString page = "algorithms/" + name + (version > 0 ? "-v" + QString::number(version) + ".html" : ".html"); launchPythonHelpWindow(page); } @@ -340,9 +311,8 @@ void InterfaceManager::launchPythonHelpWindowForFitFunction(const QString &name) void InterfaceManager::launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, const QString §ion) { QString areaPath = area.isEmpty() ? "" : area + "/"; - QString base = "interfaces/" + areaPath + (name.isEmpty() ? "index.html" : name + ".html"); + QString page = "interfaces/" + areaPath + (name.isEmpty() ? "index.html" : name + ".html"); if (!section.isEmpty()) - base += "#" + section; - launchPythonHelpWindow(base); + page += "#" + section; + launchPythonHelpWindow(page); } -#endif diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index da8c056309cc..02b4daa1e5c8 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -7,14 +7,11 @@ #include "MantidQtWidgets/Common/MantidHelpWindow.h" #include "MantidAPI/AlgorithmManager.h" #include "MantidKernel/ConfigService.h" -#include "MantidKernel/Exception.h" #include "MantidKernel/Logger.h" #include "MantidKernel/RegistrationHelper.h" #include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidDesktopServices.h" -#ifdef DOCS_QTHELP #include "MantidQtWidgets/Common/pqHelpWindow.h" -#endif #include #include #include @@ -38,19 +35,18 @@ namespace MantidQt::MantidWidgets { using std::string; using namespace MantidQt::API; -using Mantid::Kernel::Exception::NotImplementedError; +#ifdef DOCS_QTHELP REGISTER_HELPWINDOW(MantidHelpWindow) +#endif namespace { /// static logger Mantid::Kernel::Logger g_log("MantidHelpWindow"); } // namespace -#ifdef DOCS_QTHELP // initialise the help window QPointer MantidHelpWindow::g_helpWindow; -#endif /// name of the collection file itself const QString COLLECTION_FILE("MantidProject.qhc"); @@ -69,14 +65,6 @@ const QString HTML_BASE_PATH("/"); /// Page to display if nothing provided const QString DEFAULT_PAGENAME("index"); -bool MantidHelpWindow::helpWindowExists() { -#ifdef DOCS_QTHELP - return !g_helpWindow.isNull(); -#else - throw NotImplementedError("This needs to be implemented"); -#endif -} - /** * Default constructor shows the base index page. */ @@ -101,30 +89,17 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) g_log.debug("helpengine.setupData() returned false"); // create a new help window -#ifdef DOCS_QTHELP g_helpWindow = new pqHelpWindow(helpEngine, this, flags); g_helpWindow->setWindowTitle(QString("Mantid - Help")); g_helpWindow->setWindowIcon(QIcon(":/images/MantidIcon.ico")); -#else - UNUSED_ARG(flags); - throw NotImplementedError("This needs to be implemented"); -#endif // show the home page on startup auto registeredDocs = helpEngine->registeredDocumentations(); if (registeredDocs.size() > 0) { -#ifdef DOCS_QTHELP g_helpWindow->showHomePage(registeredDocs[0]); -#else - throw NotImplementedError("This needs to be implemented"); -#endif } -#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); -#else - throw NotImplementedError("This needs to be implemented"); -#endif } else { g_log.information("Without collection file redirecting help to default web browser"); } @@ -134,15 +109,11 @@ MantidHelpWindow::MantidHelpWindow(const Qt::WindowFlags &flags) void MantidHelpWindow::showHelp(const QString &url) { g_log.debug() << "open help window for \"" << url.toStdString() << "\"\n"; // bring up the help window if it is showing -#ifdef DOCS_QTHELP g_helpWindow->show(); g_helpWindow->raise(); if (!url.isEmpty()) { g_helpWindow->showPage(url); } -#else - throw NotImplementedError("This needs to be implemented"); -#endif } void MantidHelpWindow::openWebpage(const QUrl &url) { @@ -314,12 +285,8 @@ void MantidHelpWindow::shutdown() { // Deleting the object ensures the help engine's destructor is called and // avoids a segfault when workbench is closed if (helpWindowExists()) { -#ifdef DOCS_QTHELP g_helpWindow->setAttribute(Qt::WA_DeleteOnClose); g_helpWindow->close(); -#else - throw NotImplementedError("This needs to be implemented"); -#endif } else { g_log.warning("Something really wrong in MantidHelpWindow::shutdown()"); } @@ -333,7 +300,7 @@ void MantidHelpWindow::shutdown() { * * @param binDir The location of the mantid executable. */ -void MantidHelpWindow::findCollectionFile(const std::string &binDir) { +void MantidHelpWindow::findCollectionFile(std::string &binDir) { // this being empty notes the feature being disabled m_collectionFile = ""; @@ -350,9 +317,9 @@ void MantidHelpWindow::findCollectionFile(const std::string &binDir) { } // try where the builds will put it for a single configuration build - UNUSED_ARG(searchDir.cdUp()); + searchDir.cdUp(); if (searchDir.cd("docs")) { - UNUSED_ARG(searchDir.cd("qthelp")); + searchDir.cd("qthelp"); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -361,9 +328,9 @@ void MantidHelpWindow::findCollectionFile(const std::string &binDir) { } } // try where the builds will put it for a multi-configuration build - UNUSED_ARG(searchDir.cdUp()); + searchDir.cdUp(); if (searchDir.cd("docs")) { - UNUSED_ARG(searchDir.cd("qthelp")); + searchDir.cd("qthelp"); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -374,9 +341,9 @@ void MantidHelpWindow::findCollectionFile(const std::string &binDir) { // try in windows/linux install location searchDir = QDir(QString::fromStdString(binDir)); - UNUSED_ARG(searchDir.cdUp()); - UNUSED_ARG(searchDir.cd("share")); - UNUSED_ARG(searchDir.cd("doc")); + searchDir.cdUp(); + searchDir.cd("share"); + searchDir.cd("doc"); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -386,10 +353,10 @@ void MantidHelpWindow::findCollectionFile(const std::string &binDir) { // try a special place for mac/osx searchDir = QDir(QString::fromStdString(binDir)); - UNUSED_ARG(searchDir.cdUp()); - UNUSED_ARG(searchDir.cdUp()); - UNUSED_ARG(searchDir.cd("share")); - UNUSED_ARG(searchDir.cd("doc")); + searchDir.cdUp(); + searchDir.cdUp(); + searchDir.cd("share"); + searchDir.cd("doc"); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { From ca0a981a9a5721f62f6dc06112588a73423503c4 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 18 Dec 2024 08:34:24 -0500 Subject: [PATCH 11/28] Reverted changes. --- qt/widgets/common/CMakeLists.txt | 2 +- .../common/inc/MantidQtWidgets/Common/PythonHelpBridge.h | 2 ++ qt/widgets/common/src/MantidHelpWindow.cpp | 4 ++-- qt/widgets/common/src/PythonHelpBridge.cpp | 2 +- qt/widgets/common/src/PythonHelpWindow.cpp | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 3778cd841eb5..1cb748107ed7 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -217,7 +217,7 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/PropertyWidget.h - inc/MantidQtWidgets/Common/PythonBridge.h + inc/MantidQtWidgets/Common/PythonHelpBridge.h inc/MantidQtWidgets/Common/PythonHelpWindow.h inc/MantidQtWidgets/Common/PythonRunner.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h index 6d1084094387..ea26e0dd8175 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h @@ -1,4 +1,6 @@ #pragma once + +#include "DllOption.h" #include class PythonHelpBridge { diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index 02b4daa1e5c8..1adf6ec6c484 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -31,14 +31,13 @@ #include #include +#ifdef DOCS_QTHELP namespace MantidQt::MantidWidgets { using std::string; using namespace MantidQt::API; -#ifdef DOCS_QTHELP REGISTER_HELPWINDOW(MantidHelpWindow) -#endif namespace { /// static logger @@ -382,3 +381,4 @@ void MantidHelpWindow::determineFileLocs() { void MantidHelpWindow::warning(const QString &msg) { g_log.warning(msg.toStdString()); } } // namespace MantidQt::MantidWidgets +#endif diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp index 412b23481bee..567719507e0a 100644 --- a/qt/widgets/common/src/PythonHelpBridge.cpp +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -1,4 +1,4 @@ -#include "PythonHelpBridge.h" +#include "MantidQtWidgets/Common/PythonHelpBridge.h" #include #include diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp index 53e0c4265d95..f073272a2f0d 100644 --- a/qt/widgets/common/src/PythonHelpWindow.cpp +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -8,7 +8,6 @@ namespace MantidWidgets { #ifndef DOCS_QTHELP REGISTER_HELPWINDOW(PythonHelpWindow) -#endif PythonHelpWindow::PythonHelpWindow() : MantidQt::API::MantidHelpInterface() {} @@ -88,3 +87,4 @@ void PythonHelpWindow::shutdown() { } // namespace MantidWidgets } // namespace MantidQt +#endif From 2a6b4b013f064af764e15ae002ccc75abd56b504 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 18 Dec 2024 12:28:54 -0500 Subject: [PATCH 12/28] Some more changes to hopefully fix build issue --- .../common/inc/MantidQtWidgets/Common/PythonHelpWindow.h | 4 ++-- qt/widgets/common/src/PythonHelpWindow.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h index c0bdf6db28ba..acf5e0c13986 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h @@ -1,6 +1,6 @@ #pragma once -#include "DllOption.h" +#include "MantidQtWidgets/Common/DllOption.h" #include "MantidQtWidgets/Common/MantidHelpInterface.h" #include #include @@ -9,7 +9,7 @@ namespace MantidQt { namespace MantidWidgets { -class PythonHelpWindow : public MantidQt::API::MantidHelpInterface { +class EXPORT_OPT_MANTIDQT_COMMON PythonHelpWindow : public MantidQt::API::MantidHelpInterface { public: PythonHelpWindow(); void showPage(const std::string &url = std::string()) override; diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp index f073272a2f0d..db588d776215 100644 --- a/qt/widgets/common/src/PythonHelpWindow.cpp +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -3,10 +3,10 @@ #include #include +#ifndef DOCS_QTHELP namespace MantidQt { namespace MantidWidgets { -#ifndef DOCS_QTHELP REGISTER_HELPWINDOW(PythonHelpWindow) PythonHelpWindow::PythonHelpWindow() : MantidQt::API::MantidHelpInterface() {} From a87a85db23a3672051665adb1fd0bb190f0a0306 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 18 Dec 2024 13:19:41 -0500 Subject: [PATCH 13/28] Another update to PythonHelpWindow --- qt/widgets/common/src/PythonHelpWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp index db588d776215..53e0c4265d95 100644 --- a/qt/widgets/common/src/PythonHelpWindow.cpp +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -3,11 +3,12 @@ #include #include -#ifndef DOCS_QTHELP namespace MantidQt { namespace MantidWidgets { +#ifndef DOCS_QTHELP REGISTER_HELPWINDOW(PythonHelpWindow) +#endif PythonHelpWindow::PythonHelpWindow() : MantidQt::API::MantidHelpInterface() {} @@ -87,4 +88,3 @@ void PythonHelpWindow::shutdown() { } // namespace MantidWidgets } // namespace MantidQt -#endif From 0ff65c565913ffab7efa2dfe61b1f60ceb3229b7 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 18 Dec 2024 13:40:51 -0500 Subject: [PATCH 14/28] Get the code to compile --- .../MantidQtWidgets/Common/MantidHelpWindow.h | 5 +--- qt/widgets/common/src/InterfaceManager.cpp | 4 +++ qt/widgets/common/src/MantidHelpWindow.cpp | 30 ++++++++++--------- qt/widgets/common/src/PythonHelpWindow.cpp | 2 ++ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h index 84136b8e7ecc..9527d28f7714 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h @@ -16,9 +16,8 @@ class QHelpEngine; class QString; class QWidget; -#ifdef DOCS_QTHELP class pqHelpWindow; -#endif + namespace MantidQt { namespace MantidWidgets { @@ -55,10 +54,8 @@ public slots: /// The full path of the collection file. std::string m_collectionFile; -#ifdef DOCS_QTHELP /// The window that renders the help information static QPointer g_helpWindow; -#endif /// Whether this is the very first startup of the helpwindow. bool m_firstRun; diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 244ab11f0230..4349c3b4c278 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -281,7 +281,11 @@ void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QStrin void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } void InterfaceManager::closeHelpWindow() { +#ifdef DOCS_QTHELP if (MantidHelpWindow::helpWindowExists()) { +#else + if (true) { +#endif auto window = createHelpWindow(); if (window) window->shutdown(); diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index 1adf6ec6c484..a49ff98b4bfd 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -31,13 +31,14 @@ #include #include -#ifdef DOCS_QTHELP namespace MantidQt::MantidWidgets { using std::string; using namespace MantidQt::API; +#ifdef DOCS_QTHELP REGISTER_HELPWINDOW(MantidHelpWindow) +#endif namespace { /// static logger @@ -64,6 +65,8 @@ const QString HTML_BASE_PATH("/"); /// Page to display if nothing provided const QString DEFAULT_PAGENAME("index"); +bool MantidHelpWindow::helpWindowExists() { return !g_helpWindow.isNull(); } + /** * Default constructor shows the base index page. */ @@ -299,7 +302,7 @@ void MantidHelpWindow::shutdown() { * * @param binDir The location of the mantid executable. */ -void MantidHelpWindow::findCollectionFile(std::string &binDir) { +void MantidHelpWindow::findCollectionFile(const std::string &binDir) { // this being empty notes the feature being disabled m_collectionFile = ""; @@ -316,9 +319,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } // try where the builds will put it for a single configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -327,9 +330,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } } // try where the builds will put it for a multi-configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -340,9 +343,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try in windows/linux install location searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -352,10 +355,10 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try a special place for mac/osx searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -381,4 +384,3 @@ void MantidHelpWindow::determineFileLocs() { void MantidHelpWindow::warning(const QString &msg) { g_log.warning(msg.toStdString()); } } // namespace MantidQt::MantidWidgets -#endif diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp index 53e0c4265d95..7504c9ad9fc7 100644 --- a/qt/widgets/common/src/PythonHelpWindow.cpp +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -1,4 +1,6 @@ #include "MantidQtWidgets/Common/PythonHelpWindow.h" +#include "MantidKernel/RegistrationHelper.h" +#include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/PythonHelpBridge.h" #include #include From 7ee369af7ec5e231e823352aa417cb41d68e12e4 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 18 Dec 2024 15:52:36 -0500 Subject: [PATCH 15/28] Updates to InterfaceManager (remove extra stuff) --- .../MantidQtWidgets/Common/InterfaceManager.h | 50 ++----------- qt/widgets/common/src/InterfaceManager.cpp | 71 ------------------- 2 files changed, 6 insertions(+), 115 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index 2dbb47c4f026..ce67af50db13 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -1,9 +1,3 @@ -// Mantid Repository : https://github.com/mantidproject/mantid -// -// Copyright © 2009 ISIS Rutherford Appleton Laboratory UKRI, -// NScD Oak Ridge National Laboratory, European Spallation Source, -// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS -// SPDX - License - Identifier: GPL - 3.0 + #pragma once //---------------------------------- @@ -45,12 +39,12 @@ class UserSubWindow; class MantidHelpInterface; /** - This class is responsible for creating the correct dialog for an algorithm. - If no specialized version is registered for that algorithm then the default is created. - - @author Martyn Gigg, Tessella Support Services plc - @date 24/02/2009 -*/ + * This class is responsible for managing algorithm dialogs and interface windows. + * It also provides a mechanism for registering help window factories. + * + * @author Martyn Gigg + * @date 24/02/2009 + */ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { public: @@ -72,32 +66,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Create a new instance of the correct type of UserSubWindow UserSubWindow *createSubWindow(const QString &interface_name, QWidget *parent = nullptr, bool isWindow = true); - /** - * Function that instantiates the help window. - * @return the help window - */ - MantidHelpInterface *createHelpWindow() const; - - /// Show a help page by URL - void showHelpPage(const QString &url = QString()); - - /// Show algorithm help by name and version - void showAlgorithmHelp(const QString &name, const int version = -1); - - /// Show concept help by name - void showConceptHelp(const QString &name); - - /// Show fit function help - void showFitFunctionHelp(const QString &name = QString()); - - /** - * @param name of interface to show help for - * @param area - folder for documentation in the interfaces directory - * @param section - section in the HTML document - */ - void showCustomInterfaceHelp(const QString &name, const QString &area = QString(), - const QString §ion = QString()); - /// Open a web page by URL void showWebPage(const QString &url); @@ -127,12 +95,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; - - void launchPythonHelpWindow(const QString &relativePage); - void launchPythonHelpWindowForAlgorithm(const QString &name, int version = -1); - void launchPythonHelpWindowForConcept(const QString &name); - void launchPythonHelpWindowForFitFunction(const QString &name); - void launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, const QString §ion); }; } // namespace API diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 4349c3b4c278..7a006745739b 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -240,83 +240,12 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } } -void InterfaceManager::showHelpPage(const QString &url) { - // Original behavior - auto window = createHelpWindow(); - window->showPage(url); -} - -void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { - auto window = createHelpWindow(); - if (window) - window->showAlgorithm(name, version); - else - launchPythonHelpWindowForAlgorithm(name, version); -} - -void InterfaceManager::showConceptHelp(const QString &name) { - auto window = createHelpWindow(); - if (window) - window->showConcept(name); - else - launchPythonHelpWindowForConcept(name); -} - -void InterfaceManager::showFitFunctionHelp(const QString &name) { - auto window = createHelpWindow(); - if (window) - window->showFitFunction(name); - else - launchPythonHelpWindowForFitFunction(name); -} - -void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { - auto window = createHelpWindow(); - if (window) - window->showCustomInterface(name, area, section); - else - launchPythonHelpWindowForCustomInterface(name, area, section); -} - void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } void InterfaceManager::closeHelpWindow() { -#ifdef DOCS_QTHELP if (MantidHelpWindow::helpWindowExists()) { -#else - if (true) { -#endif auto window = createHelpWindow(); if (window) window->shutdown(); } } - -void InterfaceManager::launchPythonHelpWindow(const QString &relativePage) { - static PythonHelpBridge bridge; - bridge.showHelpPage(relativePage.toStdString()); -} - -void InterfaceManager::launchPythonHelpWindowForAlgorithm(const QString &name, int version) { - QString page = "algorithms/" + name + (version > 0 ? "-v" + QString::number(version) + ".html" : ".html"); - launchPythonHelpWindow(page); -} - -void InterfaceManager::launchPythonHelpWindowForConcept(const QString &name) { - QString page = name.isEmpty() ? "concepts/index.html" : "concepts/" + name + ".html"; - launchPythonHelpWindow(page); -} - -void InterfaceManager::launchPythonHelpWindowForFitFunction(const QString &name) { - QString page = name.isEmpty() ? "fitting/fitfunctions/index.html" : "fitting/fitfunctions/" + name + ".html"; - launchPythonHelpWindow(page); -} - -void InterfaceManager::launchPythonHelpWindowForCustomInterface(const QString &name, const QString &area, - const QString §ion) { - QString areaPath = area.isEmpty() ? "" : area + "/"; - QString page = "interfaces/" + areaPath + (name.isEmpty() ? "index.html" : name + ".html"); - if (!section.isEmpty()) - page += "#" + section; - launchPythonHelpWindow(page); -} From 59da208054bbdd48d5cf17742309003ac6d133a0 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Wed, 18 Dec 2024 16:11:24 -0500 Subject: [PATCH 16/28] Messed up in my last changes to InterfaceManager --- .../MantidQtWidgets/Common/InterfaceManager.h | 67 ++++++++++++++----- qt/widgets/common/src/InterfaceManager.cpp | 28 +++++++- 2 files changed, 76 insertions(+), 19 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index ce67af50db13..5e9d058ea440 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -1,9 +1,16 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2009 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + #pragma once //---------------------------------- // Includes //---------------------------------- #include "DllOption.h" +// #include "MantidKernel/SingletonHolder.h" #include "MantidKernel/Instantiator.h" #include @@ -39,12 +46,14 @@ class UserSubWindow; class MantidHelpInterface; /** - * This class is responsible for managing algorithm dialogs and interface windows. - * It also provides a mechanism for registering help window factories. - * - * @author Martyn Gigg - * @date 24/02/2009 - */ + This class is responsible for creating the correct dialog for an algorithm. + If + no specialized version is registered for that algorithm then the default is + created + + @author Martyn Gigg, Tessella Support Services plc + @date 24/02/2009 +*/ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { public: @@ -66,10 +75,36 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Create a new instance of the correct type of UserSubWindow UserSubWindow *createSubWindow(const QString &interface_name, QWidget *parent = nullptr, bool isWindow = true); - /// Open a web page by URL + /** + * Function that instantiates the help window. + * @return the help window + */ + MantidHelpInterface *createHelpWindow() const; + + /// @param url Relative URL of help page to show. + void showHelpPage(const QString &url = QString()); + + /// @param name of algorithm to show help for + /// @param version of algorithm + void showAlgorithmHelp(const QString &name, const int version = -1); + + /// @param name of concept to show help for + void showConceptHelp(const QString &name); + + /// @param name of fit function to show help for + void showFitFunctionHelp(const QString &name = QString()); + + /** + * @param name of interface to show help for + * @param area - folder for documentation in the interfaces directory + * @param section - section in the html document + **/ + void showCustomInterfaceHelp(const QString &name, const QString &area = QString(), + const QString §ion = QString()); + + /// @param url of web page to open in browser void showWebPage(const QString &url); - /// Close the active help window void closeHelpWindow(); /** @@ -86,7 +121,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Constructor InterfaceManager(); - /// Destructor virtual ~InterfaceManager(); @@ -96,15 +130,14 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { /// Handle to the help window factory static Mantid::Kernel::AbstractInstantiator *m_helpViewer; }; - } // namespace API } // namespace MantidQt /// Used to register help window -#define REGISTER_HELPWINDOW(TYPE) \ - namespace { \ - Mantid::Kernel::RegistrationHelper \ - register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( \ - new Mantid::Kernel::Instantiator())), \ - 0)); \ - } +#define REGISTER_HELPWINDOW(TYPE) +namespace { +Mantid::Kernel::RegistrationHelper + register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( + new Mantid::Kernel::Instantiator())), + 0)); +} diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 7a006745739b..675cf00ed9f3 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -240,12 +240,36 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { } } +void InterfaceManager::showHelpPage(const QString &url) { + auto window = createHelpWindow(); + window->showPage(url); +} + +void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { + auto window = createHelpWindow(); + window->showAlgorithm(name, version); +} + +void InterfaceManager::showConceptHelp(const QString &name) { + auto window = createHelpWindow(); + window->showConcept(name); +} + +void InterfaceManager::showFitFunctionHelp(const QString &name) { + auto window = createHelpWindow(); + window->showFitFunction(name); +} + +void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { + auto window = createHelpWindow(); + window->showCustomInterface(name, area, section); +} + void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } void InterfaceManager::closeHelpWindow() { if (MantidHelpWindow::helpWindowExists()) { auto window = createHelpWindow(); - if (window) - window->shutdown(); + window->shutdown(); } } From 7c776f61cbb989925eb660e1919ed440daacba9a Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 18 Dec 2024 16:13:43 -0500 Subject: [PATCH 17/28] Change how module is written in code --- .../mantidqt/widgets/helpwindow/__init__.py | 0 qt/widgets/common/src/PythonHelpBridge.cpp | 14 +++++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp index 567719507e0a..bb1b0c8ef5c7 100644 --- a/qt/widgets/common/src/PythonHelpBridge.cpp +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -1,22 +1,30 @@ #include "MantidQtWidgets/Common/PythonHelpBridge.h" #include +#include #include +namespace { // anonymous +// name of the module to import the bridge +const std::string MOD_NAME("mantidqt.widgets.helpwindow.helpwindowbridge"); +// python::str version of the module +const boost::python::str MOD_NAME_PY(MOD_NAME); +} // namespace + PythonHelpBridge::PythonHelpBridge() { Py_Initialize(); try { boost::python::object main = boost::python::import("__main__"); boost::python::object global = main.attr("__dict__"); - boost::python::import("helpwindowbridge"); + boost::python::import(MOD_NAME_PY); } catch (boost::python::error_already_set &) { PyErr_Print(); - throw std::runtime_error("Failed to import 'helpwindowbridge' Python module."); + throw std::runtime_error("Failed to import '" + MOD_NAME + "' module."); } } void PythonHelpBridge::showHelpPage(const std::string &relative_url) { try { - boost::python::object module = boost::python::import("helpwindowbridge"); + boost::python::object module = boost::python::import(MOD_NAME_PY); module.attr("show_help_page")(relative_url); } catch (boost::python::error_already_set &) { PyErr_Print(); From 6c0c0d121b36ffbc21053e6f8c6f124f2e8d6552 Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Wed, 18 Dec 2024 16:21:07 -0500 Subject: [PATCH 18/28] Fix pre-processor macro --- .../inc/MantidQtWidgets/Common/InterfaceManager.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index 5e9d058ea440..4b6dce8fc453 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -134,10 +134,10 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { } // namespace MantidQt /// Used to register help window -#define REGISTER_HELPWINDOW(TYPE) -namespace { -Mantid::Kernel::RegistrationHelper - register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( - new Mantid::Kernel::Instantiator())), - 0)); -} +#define REGISTER_HELPWINDOW(TYPE) \ + namespace { \ + Mantid::Kernel::RegistrationHelper \ + register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( \ + new Mantid::Kernel::Instantiator())), \ + 0)); \ + } From 94e27fb09634967b16cc5824091d29e7a403ce1f Mon Sep 17 00:00:00 2001 From: Pete Peterson Date: Thu, 19 Dec 2024 09:59:23 -0500 Subject: [PATCH 19/28] Add pyqtwebengine dependency for new help window --- conda/recipes/mantid-developer/meta.yaml | 1 + conda/recipes/mantidqt/meta.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/conda/recipes/mantid-developer/meta.yaml b/conda/recipes/mantid-developer/meta.yaml index e3a46b0ff94c..69aedfb7fe27 100644 --- a/conda/recipes/mantid-developer/meta.yaml +++ b/conda/recipes/mantid-developer/meta.yaml @@ -37,6 +37,7 @@ requirements: - pycifrw - pydantic - pyqt {{ pyqt }} + - pyqtwebengine - python-dateutil {{ python_dateutil }} - python {{ python }} - python.app # [osx] diff --git a/conda/recipes/mantidqt/meta.yaml b/conda/recipes/mantidqt/meta.yaml index 8eff03bde3ea..4ffd838b9cdc 100644 --- a/conda/recipes/mantidqt/meta.yaml +++ b/conda/recipes/mantidqt/meta.yaml @@ -26,6 +26,7 @@ requirements: - setuptools # [build_platform != target_platform] - numpy {{ numpy }} # [build_platform != target_platform] - pyqt {{ pyqt }} # [build_platform != target_platform] + - pyqtwebengine # [build_platform != target_platform] - qt-main {{ qt_main }} # [build_platform != target_platform] - sip {{ sip }} # [build_platform != target_platform] - {{ cdt('mesa-libgl-devel') }} # [linux] From 50870c49d5ec2db334b4e5c67bf7432ee9b371f7 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Mon, 23 Dec 2024 13:54:46 -0500 Subject: [PATCH 20/28] Some fixes, seg fault investigation on local --- .../widgets/helpwindow/helpwindowpresenter.py | 28 ++++++++--- .../widgets/helpwindow/helpwindowview.py | 46 +++++++++++++++-- qt/widgets/common/src/AlgorithmDialog.cpp | 7 +-- qt/widgets/common/src/InterfaceManager.cpp | 50 ++++++++++++++++--- 4 files changed, 112 insertions(+), 19 deletions(-) diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py index 941b2f6ae7f1..e300d102b28e 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py @@ -1,20 +1,36 @@ -from qtpy.QtWidgets import QApplication -import sys from .helpwindowview import HelpWindowView from .helpwindowmodel import HelpWindowModel class HelpWindowPresenter: - def __init__(self): + def __init__(self, parent_app=None): + """ + Initialize the presenter for the Help Window. + + :param parent_app: Optional parent application to tie the lifecycle of this presenter. + """ self.model = HelpWindowModel() self.view = HelpWindowView(self) - self.app = QApplication(sys.argv) + self.parent_app = parent_app + self._window_open = False + + if self.parent_app: + self.parent_app.aboutToQuit.connect(self.cleanup) def show_help_window(self): """Show the help window.""" - self.view.display() - sys.exit(self.app.exec_()) + if not self._window_open: + self._window_open = True + self.view.display() def on_close(self): """Handle actions when the window is closed.""" print("Help window closed.") + self.cleanup() + + def cleanup(self): + """Ensure proper cleanup of resources.""" + if self._window_open: + self._window_open = False + print("Cleaning up Help Window resources.") + self.view.close() diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py index ab86e552ccc0..dbe9e9951ffe 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -1,7 +1,8 @@ import os -from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QWidget +from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QToolBar, QPushButton, QWidget from qtpy.QtWebEngineWidgets import QWebEngineView from qtpy.QtCore import QUrl +from qtpy.QtGui import QIcon class HelpWindowView(QMainWindow): @@ -11,24 +12,61 @@ def __init__(self, presenter): self.setWindowTitle("Python Help Window") self.resize(800, 600) + # Web browser widget self.browser = QWebEngineView() - # Determine initial URL: + # Determine initial URL local_docs_base = os.environ.get("MANTID_LOCAL_DOCS_BASE") if local_docs_base and os.path.isdir(local_docs_base): - # Use local docs if available index_path = os.path.join(local_docs_base, "index.html") self.browser.setUrl(QUrl.fromLocalFile(index_path)) else: - # Fallback to online docs self.browser.setUrl(QUrl("https://docs.mantidproject.org/")) + # Toolbar with navigation buttons + self.toolbar = QToolBar("Navigation") + self.addToolBar(self.toolbar) + + # Back button + back_button = QPushButton() + back_button.setIcon(QIcon.fromTheme("go-previous")) + back_button.setToolTip("Go Back") + back_button.clicked.connect(self.browser.back) + self.toolbar.addWidget(back_button) + + # Forward button + forward_button = QPushButton() + forward_button.setIcon(QIcon.fromTheme("go-next")) + forward_button.setToolTip("Go Forward") + forward_button.clicked.connect(self.browser.forward) + self.toolbar.addWidget(forward_button) + + # Home button + home_button = QPushButton() + home_button.setIcon(QIcon.fromTheme("go-home")) + home_button.setToolTip("Go Home") + home_button.clicked.connect(self.go_home) + self.toolbar.addWidget(home_button) + + # Reload button + reload_button = QPushButton() + reload_button.setIcon(QIcon.fromTheme("view-refresh")) + reload_button.setToolTip("Reload") + reload_button.clicked.connect(self.browser.reload) + self.toolbar.addWidget(reload_button) + + # Layout layout = QVBoxLayout() layout.addWidget(self.browser) + container = QWidget() container.setLayout(layout) self.setCentralWidget(container) + def go_home(self): + """Navigate to the home page.""" + self.browser.setUrl(QUrl("https://docs.mantidproject.org/")) + def display(self): """Show the help window.""" self.show() diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 564afbf8f6cd..0df7baa78868 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -13,7 +13,7 @@ #include "MantidQtWidgets/Common/AlgorithmDialog.h" #include "MantidQtWidgets/Common/AlgorithmInputHistory.h" #include "MantidQtWidgets/Common/FilePropertyWidget.h" -#include "MantidQtWidgets/Common/HelpWindow.h" +#include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidWidget.h" #include "MantidQtWidgets/Common/PropertyWidget.h" @@ -705,13 +705,14 @@ void AlgorithmDialog::reject() { * A slot to handle the help button click */ void AlgorithmDialog::helpClicked() { + __builtin_trap(); // determine the version to show int version(-1); // the latest version if (m_algorithm) version = m_algorithm->version(); - // bring up the help window - HelpWindow::showAlgorithm(m_algName, version); + // use interface manager instead of help window + MantidQt::API::InterfaceManager().showAlgorithmHelp(m_algName, version); } //------------------------------------------------------------------------------------------------- diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index 675cf00ed9f3..d65f338cf120 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -24,7 +24,9 @@ #include "MantidKernel/Logger.h" #include +#include #include +#include #include using namespace MantidQt::API; @@ -225,6 +227,9 @@ void InterfaceManager::registerHelpWindowFactory(Mantid::Kernel::AbstractInstant } MantidHelpInterface *InterfaceManager::createHelpWindow() const { + QString localDocs = qEnvironmentVariable("MANTID_LOCAL_DOCS_BASE"); + bool localAvailable = !localDocs.isEmpty() && QDir(localDocs).exists(); + if (m_helpViewer == nullptr) { if (!offlineHelpMsgDisplayed) { g_log.information("Offline help is not available in this version of Workbench."); @@ -235,6 +240,7 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { MantidHelpInterface *interface = this->m_helpViewer->createUnwrappedInstance(); if (!interface) { g_log.error("Error creating help window"); + return nullptr; } return interface; } @@ -242,27 +248,58 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { void InterfaceManager::showHelpPage(const QString &url) { auto window = createHelpWindow(); - window->showPage(url); + if (window) + window->showPage(url); + else + MantidDesktopServices::openUrl(url); } void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { auto window = createHelpWindow(); - window->showAlgorithm(name, version); + if (window) + window->showAlgorithm(name, version); + else { + QString url("https://docs.mantidproject.org/algorithms/"); + url += name.isEmpty() ? "index.html" : name + (version > 0 ? "-v" + QString::number(version) + ".html" : ".html"); + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showConceptHelp(const QString &name) { auto window = createHelpWindow(); - window->showConcept(name); + if (window) + window->showConcept(name); + else { + QString url("https://docs.mantidproject.org/concepts/"); + url += name.isEmpty() ? "index.html" : name + ".html"; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showFitFunctionHelp(const QString &name) { auto window = createHelpWindow(); - window->showFitFunction(name); + if (window) + window->showFitFunction(name); + else { + QString url("https://docs.mantidproject.org/fitting/fitfunctions/"); + url += name.isEmpty() ? "index.html" : name + ".html"; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { auto window = createHelpWindow(); - window->showCustomInterface(name, area, section); + if (window) + window->showCustomInterface(name, area, section); + else { + QString url("https://docs.mantidproject.org/interfaces/"); + if (!area.isEmpty()) + url += area + "/"; + url += name.isEmpty() ? "index.html" : name + ".html"; + if (!section.isEmpty()) + url += "#" + section; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } @@ -270,6 +307,7 @@ void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices:: void InterfaceManager::closeHelpWindow() { if (MantidHelpWindow::helpWindowExists()) { auto window = createHelpWindow(); - window->shutdown(); + if (window) + window->shutdown(); } } From 7248ff1d66b750c2bd9b1344c62a5dabefe9a69c Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 6 Jan 2025 10:44:18 -0500 Subject: [PATCH 21/28] Updates to fix cppcheck. --- qt/widgets/common/src/AlgorithmDialog.cpp | 12 +++++------- qt/widgets/common/src/InterfaceManager.cpp | 2 -- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 0df7baa78868..54adee6de153 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -9,6 +9,7 @@ #include "MantidKernel/DateAndTimeHelpers.h" #include "MantidKernel/IPropertySettings.h" #include "MantidKernel/Logger.h" +#include #include "MantidQtWidgets/Common/AlgorithmDialog.h" #include "MantidQtWidgets/Common/AlgorithmInputHistory.h" @@ -705,7 +706,7 @@ void AlgorithmDialog::reject() { * A slot to handle the help button click */ void AlgorithmDialog::helpClicked() { - __builtin_trap(); + std::raise(SIGTRAP); // determine the version to show int version(-1); // the latest version if (m_algorithm) @@ -892,17 +893,14 @@ QString AlgorithmDialog::getValue(QWidget *widget) { } else if (QLineEdit *textfield = qobject_cast(widget)) { return textfield->text().trimmed(); } else if (QAbstractButton *checker = qobject_cast(widget)) { - if (checker->isChecked()) - return QString("1"); - else - return QString("0"); + return checker->isChecked() ? QString("1") : QString("0"); } else if (QDateTimeEdit *dateEdit = qobject_cast(widget)) { // String in ISO8601 format /* add toUTC() to go from local time */ QString value = dateEdit->dateTime().toString(Qt::ISODate); return value; - } else if (MantidWidget *mtd_widget = qobject_cast(widget)) { + } else if (const MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here return mtd_widget->getUserInput().toString().trimmed(); - } else if (PropertyWidget *propWidget = qobject_cast(widget)) { + } else if (const PropertyWidget *propWidget = qobject_cast(widget)) { // And here return propWidget->getValue().trimmed(); } else { QMessageBox::warning(this, windowTitle(), diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index d65f338cf120..b9490b06d261 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -228,8 +228,6 @@ void InterfaceManager::registerHelpWindowFactory(Mantid::Kernel::AbstractInstant MantidHelpInterface *InterfaceManager::createHelpWindow() const { QString localDocs = qEnvironmentVariable("MANTID_LOCAL_DOCS_BASE"); - bool localAvailable = !localDocs.isEmpty() && QDir(localDocs).exists(); - if (m_helpViewer == nullptr) { if (!offlineHelpMsgDisplayed) { g_log.information("Offline help is not available in this version of Workbench."); From 5810f2c4d6d909328cb066861f96a79c858adb1c Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 6 Jan 2025 11:07:47 -0500 Subject: [PATCH 22/28] ... --- qt/widgets/common/src/AlgorithmDialog.cpp | 33 +++++++++++----------- qt/widgets/common/src/InterfaceManager.cpp | 1 - 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 54adee6de153..6454ef20a515 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -161,7 +161,7 @@ void AlgorithmDialog::saveInput() { AlgorithmInputHistory::Instance().clearAlgorithmInput(m_algName); QStringList::const_iterator pend = m_algProperties.end(); for (QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend; ++pitr) { - Mantid::Kernel::Property *p = getAlgorithmProperty(*pitr); + const Mantid::Kernel::Property *p = getAlgorithmProperty(*pitr); if (p->remember()) { QString pName = *pitr; QString value = m_propertyValueMap.value(pName); @@ -202,7 +202,7 @@ Mantid::API::IAlgorithm_sptr AlgorithmDialog::getAlgorithm() const { return m_al * Get a named property for this algorithm * @param propName :: The name of the property */ -Mantid::Kernel::Property *AlgorithmDialog::getAlgorithmProperty(const QString &propName) const { +const Mantid::Kernel::Property *AlgorithmDialog::getAlgorithmProperty(const QString &propName) const { if (m_algProperties.contains(propName)) { return m_algorithm->getProperty(propName.toStdString()); } else @@ -223,7 +223,7 @@ bool AlgorithmDialog::requiresUserInput(const QString &propName) const { return QString AlgorithmDialog::getInputValue(const QString &propName) const { QString value = m_propertyValueMap.value(propName); if (value.isEmpty()) { - Mantid::Kernel::Property *prop = getAlgorithmProperty(propName); + const Mantid::Kernel::Property *prop = getAlgorithmProperty(propName); if (prop) return QString::fromStdString(prop->getDefault()); else @@ -350,7 +350,7 @@ bool AlgorithmDialog::setPropertyValues(const QStringList &skipList) { const QString pName = *pitr; if (skipList.contains(pName)) { // For the load dialog, skips setting some properties - Mantid::Kernel::Property *p = getAlgorithmProperty(pName); + const Mantid::Kernel::Property *p = getAlgorithmProperty(pName); std::string error = p->isValid(); m_errors[pName] = QString::fromStdString(error).trimmed(); if (!error.empty()) @@ -443,7 +443,7 @@ bool AlgorithmDialog::isWidgetEnabled(const QString &propName) const { return true; // Otherwise it must be disabled but only if it is valid - Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (!property) return true; @@ -499,13 +499,13 @@ QWidget *AlgorithmDialog::tie(QWidget *widget, const QString &property, QLayout if (m_tied_properties.contains(property)) m_tied_properties.remove(property); - Mantid::Kernel::Property *prop = getAlgorithmProperty(property); + const Mantid::Kernel::Property *prop = getAlgorithmProperty(property); if (prop) { // Set a few things on the widget widget->setToolTip(QString::fromStdString(prop->documentation())); } widget->setEnabled(isWidgetEnabled(property)); - PropertyWidget *propWidget = qobject_cast(widget); + const PropertyWidget *propWidget = qobject_cast(widget); // Save in the hashes m_tied_properties.insert(property, widget); @@ -579,7 +579,7 @@ QString AlgorithmDialog::openFileDialog(const QString &propName) { void AlgorithmDialog::fillAndSetComboBox(const QString &propName, QComboBox *optionsBox) const { if (!optionsBox) return; - Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (!property) return; @@ -614,7 +614,7 @@ void AlgorithmDialog::fillLineEdit(const QString &propName, QLineEdit *textField if (!isForScript()) { textField->setText(AlgorithmInputHistory::Instance().previousInput(m_algName, propName)); } else { - Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (property && property->isValid().empty() && (m_python_arguments.contains(propName) || !property->isDefault())) { textField->setText(QString::fromStdString(property->value())); } @@ -940,7 +940,7 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) QString value = getPreviousValue(propName); - Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); // Do the right thing for the widget type if (QComboBox *opts = qobject_cast(widget)) { @@ -954,7 +954,7 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) return; } if (QAbstractButton *checker = qobject_cast(widget)) { - if (value.isEmpty() && dynamic_cast *>(property)) + if (value.isEmpty() && dynamic_cast *>(property)) value = QString::fromStdString(property->value()); checker->setChecked(value != "0"); return; @@ -972,13 +972,13 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) } QLineEdit *textfield = qobject_cast(widget); - MantidWidget *mtdwidget = qobject_cast(widget); + const MantidWidget *mtdwidget = qobject_cast(widget); if (textfield || mtdwidget) { if (!isForScript()) { if (textfield) textfield->setText(value); else - mtdwidget->setUserInput(value); + const_cast(mtdwidget)->setUserInput(value); } else { // Need to check if this is the default value as we don't fill them in if // they are @@ -986,16 +986,15 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) if (textfield) textfield->setText(value); else - mtdwidget->setUserInput(value); + const_cast(mtdwidget)->setUserInput(value); } } return; } - PropertyWidget *propWidget = qobject_cast(widget); + const PropertyWidget *propWidget = qobject_cast(widget); if (propWidget) { - propWidget->setPreviousValue(value); - + const_cast(propWidget)->setPreviousValue(value); return; } diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index b9490b06d261..abbadc961de9 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -227,7 +227,6 @@ void InterfaceManager::registerHelpWindowFactory(Mantid::Kernel::AbstractInstant } MantidHelpInterface *InterfaceManager::createHelpWindow() const { - QString localDocs = qEnvironmentVariable("MANTID_LOCAL_DOCS_BASE"); if (m_helpViewer == nullptr) { if (!offlineHelpMsgDisplayed) { g_log.information("Offline help is not available in this version of Workbench."); From a287cc0fcdff2feb12b26000a7bafef1a2f83568 Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 6 Jan 2025 11:07:47 -0500 Subject: [PATCH 23/28] ... --- qt/widgets/common/src/AlgorithmDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 6454ef20a515..66407851444d 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -898,9 +898,9 @@ QString AlgorithmDialog::getValue(QWidget *widget) { // String in ISO8601 format /* add toUTC() to go from local time */ QString value = dateEdit->dateTime().toString(Qt::ISODate); return value; - } else if (const MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here + } else if (MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here return mtd_widget->getUserInput().toString().trimmed(); - } else if (const PropertyWidget *propWidget = qobject_cast(widget)) { // And here + } else if (PropertyWidget *propWidget = qobject_cast(widget)) { // And here return propWidget->getValue().trimmed(); } else { QMessageBox::warning(this, windowTitle(), From b1cec60e467c8ee7a641ee3cc10f4f83b82f30fb Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 6 Jan 2025 13:23:38 -0500 Subject: [PATCH 24/28] fixup! ... --- qt/widgets/common/src/AlgorithmDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 66407851444d..6454ef20a515 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -898,9 +898,9 @@ QString AlgorithmDialog::getValue(QWidget *widget) { // String in ISO8601 format /* add toUTC() to go from local time */ QString value = dateEdit->dateTime().toString(Qt::ISODate); return value; - } else if (MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here + } else if (const MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here return mtd_widget->getUserInput().toString().trimmed(); - } else if (PropertyWidget *propWidget = qobject_cast(widget)) { // And here + } else if (const PropertyWidget *propWidget = qobject_cast(widget)) { // And here return propWidget->getValue().trimmed(); } else { QMessageBox::warning(this, windowTitle(), From 49f305535ca98022adaf04f1fc0198a42f5c83ce Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 6 Jan 2025 15:17:06 -0500 Subject: [PATCH 25/28] fixup! Merge branch '37248-remove-qtassistant-and-reduce-size-of-mantiddocs-package' of https://github.com/mantidproject/mantid into 37248-remove-qtassistant-and-reduce-size-of-mantiddocs-package --- qt/widgets/common/src/AlgorithmDialog.cpp | 50 ++++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 6454ef20a515..564afbf8f6cd 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -9,12 +9,11 @@ #include "MantidKernel/DateAndTimeHelpers.h" #include "MantidKernel/IPropertySettings.h" #include "MantidKernel/Logger.h" -#include #include "MantidQtWidgets/Common/AlgorithmDialog.h" #include "MantidQtWidgets/Common/AlgorithmInputHistory.h" #include "MantidQtWidgets/Common/FilePropertyWidget.h" -#include "MantidQtWidgets/Common/InterfaceManager.h" +#include "MantidQtWidgets/Common/HelpWindow.h" #include "MantidQtWidgets/Common/MantidWidget.h" #include "MantidQtWidgets/Common/PropertyWidget.h" @@ -161,7 +160,7 @@ void AlgorithmDialog::saveInput() { AlgorithmInputHistory::Instance().clearAlgorithmInput(m_algName); QStringList::const_iterator pend = m_algProperties.end(); for (QStringList::const_iterator pitr = m_algProperties.begin(); pitr != pend; ++pitr) { - const Mantid::Kernel::Property *p = getAlgorithmProperty(*pitr); + Mantid::Kernel::Property *p = getAlgorithmProperty(*pitr); if (p->remember()) { QString pName = *pitr; QString value = m_propertyValueMap.value(pName); @@ -202,7 +201,7 @@ Mantid::API::IAlgorithm_sptr AlgorithmDialog::getAlgorithm() const { return m_al * Get a named property for this algorithm * @param propName :: The name of the property */ -const Mantid::Kernel::Property *AlgorithmDialog::getAlgorithmProperty(const QString &propName) const { +Mantid::Kernel::Property *AlgorithmDialog::getAlgorithmProperty(const QString &propName) const { if (m_algProperties.contains(propName)) { return m_algorithm->getProperty(propName.toStdString()); } else @@ -223,7 +222,7 @@ bool AlgorithmDialog::requiresUserInput(const QString &propName) const { return QString AlgorithmDialog::getInputValue(const QString &propName) const { QString value = m_propertyValueMap.value(propName); if (value.isEmpty()) { - const Mantid::Kernel::Property *prop = getAlgorithmProperty(propName); + Mantid::Kernel::Property *prop = getAlgorithmProperty(propName); if (prop) return QString::fromStdString(prop->getDefault()); else @@ -350,7 +349,7 @@ bool AlgorithmDialog::setPropertyValues(const QStringList &skipList) { const QString pName = *pitr; if (skipList.contains(pName)) { // For the load dialog, skips setting some properties - const Mantid::Kernel::Property *p = getAlgorithmProperty(pName); + Mantid::Kernel::Property *p = getAlgorithmProperty(pName); std::string error = p->isValid(); m_errors[pName] = QString::fromStdString(error).trimmed(); if (!error.empty()) @@ -443,7 +442,7 @@ bool AlgorithmDialog::isWidgetEnabled(const QString &propName) const { return true; // Otherwise it must be disabled but only if it is valid - const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (!property) return true; @@ -499,13 +498,13 @@ QWidget *AlgorithmDialog::tie(QWidget *widget, const QString &property, QLayout if (m_tied_properties.contains(property)) m_tied_properties.remove(property); - const Mantid::Kernel::Property *prop = getAlgorithmProperty(property); + Mantid::Kernel::Property *prop = getAlgorithmProperty(property); if (prop) { // Set a few things on the widget widget->setToolTip(QString::fromStdString(prop->documentation())); } widget->setEnabled(isWidgetEnabled(property)); - const PropertyWidget *propWidget = qobject_cast(widget); + PropertyWidget *propWidget = qobject_cast(widget); // Save in the hashes m_tied_properties.insert(property, widget); @@ -579,7 +578,7 @@ QString AlgorithmDialog::openFileDialog(const QString &propName) { void AlgorithmDialog::fillAndSetComboBox(const QString &propName, QComboBox *optionsBox) const { if (!optionsBox) return; - const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (!property) return; @@ -614,7 +613,7 @@ void AlgorithmDialog::fillLineEdit(const QString &propName, QLineEdit *textField if (!isForScript()) { textField->setText(AlgorithmInputHistory::Instance().previousInput(m_algName, propName)); } else { - const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + Mantid::Kernel::Property *property = getAlgorithmProperty(propName); if (property && property->isValid().empty() && (m_python_arguments.contains(propName) || !property->isDefault())) { textField->setText(QString::fromStdString(property->value())); } @@ -706,14 +705,13 @@ void AlgorithmDialog::reject() { * A slot to handle the help button click */ void AlgorithmDialog::helpClicked() { - std::raise(SIGTRAP); // determine the version to show int version(-1); // the latest version if (m_algorithm) version = m_algorithm->version(); - // use interface manager instead of help window - MantidQt::API::InterfaceManager().showAlgorithmHelp(m_algName, version); + // bring up the help window + HelpWindow::showAlgorithm(m_algName, version); } //------------------------------------------------------------------------------------------------- @@ -893,14 +891,17 @@ QString AlgorithmDialog::getValue(QWidget *widget) { } else if (QLineEdit *textfield = qobject_cast(widget)) { return textfield->text().trimmed(); } else if (QAbstractButton *checker = qobject_cast(widget)) { - return checker->isChecked() ? QString("1") : QString("0"); + if (checker->isChecked()) + return QString("1"); + else + return QString("0"); } else if (QDateTimeEdit *dateEdit = qobject_cast(widget)) { // String in ISO8601 format /* add toUTC() to go from local time */ QString value = dateEdit->dateTime().toString(Qt::ISODate); return value; - } else if (const MantidWidget *mtd_widget = qobject_cast(widget)) { // Changed here + } else if (MantidWidget *mtd_widget = qobject_cast(widget)) { return mtd_widget->getUserInput().toString().trimmed(); - } else if (const PropertyWidget *propWidget = qobject_cast(widget)) { // And here + } else if (PropertyWidget *propWidget = qobject_cast(widget)) { return propWidget->getValue().trimmed(); } else { QMessageBox::warning(this, windowTitle(), @@ -940,7 +941,7 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) QString value = getPreviousValue(propName); - const Mantid::Kernel::Property *property = getAlgorithmProperty(propName); + Mantid::Kernel::Property *property = getAlgorithmProperty(propName); // Do the right thing for the widget type if (QComboBox *opts = qobject_cast(widget)) { @@ -954,7 +955,7 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) return; } if (QAbstractButton *checker = qobject_cast(widget)) { - if (value.isEmpty() && dynamic_cast *>(property)) + if (value.isEmpty() && dynamic_cast *>(property)) value = QString::fromStdString(property->value()); checker->setChecked(value != "0"); return; @@ -972,13 +973,13 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) } QLineEdit *textfield = qobject_cast(widget); - const MantidWidget *mtdwidget = qobject_cast(widget); + MantidWidget *mtdwidget = qobject_cast(widget); if (textfield || mtdwidget) { if (!isForScript()) { if (textfield) textfield->setText(value); else - const_cast(mtdwidget)->setUserInput(value); + mtdwidget->setUserInput(value); } else { // Need to check if this is the default value as we don't fill them in if // they are @@ -986,15 +987,16 @@ void AlgorithmDialog::setPreviousValue(QWidget *widget, const QString &propName) if (textfield) textfield->setText(value); else - const_cast(mtdwidget)->setUserInput(value); + mtdwidget->setUserInput(value); } } return; } - const PropertyWidget *propWidget = qobject_cast(widget); + PropertyWidget *propWidget = qobject_cast(widget); if (propWidget) { - const_cast(propWidget)->setPreviousValue(value); + propWidget->setPreviousValue(value); + return; } From f6fabc5f4cf347d79739cafd9f692665f9380726 Mon Sep 17 00:00:00 2001 From: darshdinger Date: Thu, 5 Dec 2024 10:25:20 -0500 Subject: [PATCH 26/28] Changes to facilitate new HelpWindow design Some updates to make branch current, tests in next Most recent changes. Updating branch with latest changes Make qtassistant a compile time option This removes the pointer to the qtassistant wrapper as dependent on the variable QT_DOCS. The default behavior is to keep the current functionality. Hopefully this is a compile time implementation Smal fixes Final updates More updates and Pete's changes Revert some of Petes changes and some more updates Reverted changes. Some more changes to hopefully fix build issue Another update to PythonHelpWindow Get the code to compile Updates to InterfaceManager (remove extra stuff) Messed up in my last changes to InterfaceManager Change how module is written in code Fix pre-processor macro Add pyqtwebengine dependency for new help window Some fixes, seg fault investigation on local Updates to fix cppcheck. ... ... --- CMakeLists.txt | 2 + .../CMake/CppCheck_Suppressions.txt.in | 11 --- conda/recipes/mantid-developer/meta.yaml | 1 + conda/recipes/mantidqt/meta.yaml | 1 + docs/CMakeLists.txt | 1 - .../mantidqt/widgets/helpwindow/__init__.py | 0 .../widgets/helpwindow/helpwindowbridge.py | 36 ++++++++ .../widgets/helpwindow/helpwindowmodel.py | 7 ++ .../widgets/helpwindow/helpwindowpresenter.py | 36 ++++++++ .../widgets/helpwindow/helpwindowview.py | 77 ++++++++++++++++ qt/widgets/common/CMakeLists.txt | 4 + .../MantidQtWidgets/Common/InterfaceManager.h | 2 +- .../MantidQtWidgets/Common/MantidHelpWindow.h | 15 ++- .../MantidQtWidgets/Common/PythonHelpBridge.h | 10 ++ .../MantidQtWidgets/Common/PythonHelpWindow.h | 32 +++++++ qt/widgets/common/src/InterfaceManager.cpp | 51 ++++++++-- qt/widgets/common/src/MantidHelpWindow.cpp | 28 +++--- qt/widgets/common/src/PythonHelpBridge.cpp | 33 +++++++ qt/widgets/common/src/PythonHelpWindow.cpp | 92 +++++++++++++++++++ 19 files changed, 399 insertions(+), 40 deletions(-) create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py create mode 100644 qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py create mode 100644 qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h create mode 100644 qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h create mode 100644 qt/widgets/common/src/PythonHelpBridge.cpp create mode 100644 qt/widgets/common/src/PythonHelpWindow.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d550859d9e..1c793739687e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,8 @@ endif() # Docs requirements option(ENABLE_DOCS "Enable Building user and developer documentation" ON) if(ENABLE_DOCS) + option(DOCS_QTHELP "If enabled add a target to build the qthelp documentation for qtassistant" ON) + find_package(Sphinx REQUIRED) # run python to see if the theme is installed execute_process( diff --git a/buildconfig/CMake/CppCheck_Suppressions.txt.in b/buildconfig/CMake/CppCheck_Suppressions.txt.in index 985876043828..8f80c7f33cd5 100644 --- a/buildconfig/CMake/CppCheck_Suppressions.txt.in +++ b/buildconfig/CMake/CppCheck_Suppressions.txt.in @@ -1157,17 +1157,6 @@ constVariableReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/InstrumentSelec constVariableReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/ListPropertyWidget.cpp:46 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/FitDomain.h:35 virtualCallInConstructor:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/ManageUserDirectories.h:39 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:318 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:320 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:329 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:331 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:342 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:343 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:344 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:354 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:355 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:356 -ignoredReturnErrorCode:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:357 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/Message.h:52 returnByReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/inc/MantidQtWidgets/Common/Message.h:56 constParameterReference:${CMAKE_SOURCE_DIR}/qt/widgets/common/src/MantidHelpWindow.cpp:301 diff --git a/conda/recipes/mantid-developer/meta.yaml b/conda/recipes/mantid-developer/meta.yaml index e3a46b0ff94c..69aedfb7fe27 100644 --- a/conda/recipes/mantid-developer/meta.yaml +++ b/conda/recipes/mantid-developer/meta.yaml @@ -37,6 +37,7 @@ requirements: - pycifrw - pydantic - pyqt {{ pyqt }} + - pyqtwebengine - python-dateutil {{ python_dateutil }} - python {{ python }} - python.app # [osx] diff --git a/conda/recipes/mantidqt/meta.yaml b/conda/recipes/mantidqt/meta.yaml index 8eff03bde3ea..4ffd838b9cdc 100644 --- a/conda/recipes/mantidqt/meta.yaml +++ b/conda/recipes/mantidqt/meta.yaml @@ -26,6 +26,7 @@ requirements: - setuptools # [build_platform != target_platform] - numpy {{ numpy }} # [build_platform != target_platform] - pyqt {{ pyqt }} # [build_platform != target_platform] + - pyqtwebengine # [build_platform != target_platform] - qt-main {{ qt_main }} # [build_platform != target_platform] - sip {{ sip }} # [build_platform != target_platform] - {{ cdt('mesa-libgl-devel') }} # [linux] diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 238d485d76e7..c47d6707ff10 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -9,7 +9,6 @@ set(DOCS_MATH_EXT ) set_property(CACHE DOCS_MATH_EXT PROPERTY STRINGS "sphinx.ext.imgmath" "sphinx.ext.mathjax") option(DOCS_PLOTDIRECTIVE "If enabled include plots generated with the plot directive. " OFF) -option(DOCS_QTHELP "If enabled add a target to build the qthelp documentation" ON) option(SPHINX_WARNINGS_AS_ERRORS "non-zero exit if there are sphinx warnings" ON) option(SPHINX_FRESH_ENV "Don't use a saved environment, but rebuild it completely" ON) diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py new file mode 100644 index 000000000000..d8525f57a607 --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowbridge.py @@ -0,0 +1,36 @@ +import os +from mantidqt.widgets.helpwindow.helpwindowpresenter import HelpWindowPresenter +from qtpy.QtCore import QUrl + +_presenter = None + +online_base_url = "https://docs.mantidproject.org/" +# NOTE: Once you build the html docs using the command ninja docs-html, you will need to +# use the command export MANTID_LOCAL_DOCS_BASE="/path/to/build/docs/html". +# If this it not set, this will default to the online docs. +local_docs_base = os.environ.get("MANTID_LOCAL_DOCS_BASE") # e.g. /path/to/build/docs/html + + +def show_help_page(relative_url): + """ + Show the help window at the given relative URL path, e.g. "algorithms/Load-v1.html". + """ + global _presenter + if _presenter is None: + _presenter = HelpWindowPresenter() + + # Default to index.html if no specific file given + if not relative_url or not relative_url.endswith(".html"): + relative_url = "index.html" + + if local_docs_base and os.path.isdir(local_docs_base): + # Use local docs + full_path = os.path.join(local_docs_base, relative_url) + file_url = QUrl.fromLocalFile(full_path) + _presenter.view.browser.setUrl(file_url) + else: + # Use online docs + full_url = online_base_url + relative_url + _presenter.view.browser.setUrl(QUrl(full_url)) + + _presenter.show_help_window() diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py new file mode 100644 index 000000000000..15ef280736ac --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowmodel.py @@ -0,0 +1,7 @@ +class HelpWindowModel: + def __init__(self): + self.help_url = "https://docs.mantidproject.org/" + + def get_help_url(self): + """Get the help documentation URL.""" + return self.help_url diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py new file mode 100644 index 000000000000..e300d102b28e --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowpresenter.py @@ -0,0 +1,36 @@ +from .helpwindowview import HelpWindowView +from .helpwindowmodel import HelpWindowModel + + +class HelpWindowPresenter: + def __init__(self, parent_app=None): + """ + Initialize the presenter for the Help Window. + + :param parent_app: Optional parent application to tie the lifecycle of this presenter. + """ + self.model = HelpWindowModel() + self.view = HelpWindowView(self) + self.parent_app = parent_app + self._window_open = False + + if self.parent_app: + self.parent_app.aboutToQuit.connect(self.cleanup) + + def show_help_window(self): + """Show the help window.""" + if not self._window_open: + self._window_open = True + self.view.display() + + def on_close(self): + """Handle actions when the window is closed.""" + print("Help window closed.") + self.cleanup() + + def cleanup(self): + """Ensure proper cleanup of resources.""" + if self._window_open: + self._window_open = False + print("Cleaning up Help Window resources.") + self.view.close() diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py new file mode 100644 index 000000000000..dbe9e9951ffe --- /dev/null +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -0,0 +1,77 @@ +import os +from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QToolBar, QPushButton, QWidget +from qtpy.QtWebEngineWidgets import QWebEngineView +from qtpy.QtCore import QUrl +from qtpy.QtGui import QIcon + + +class HelpWindowView(QMainWindow): + def __init__(self, presenter): + super().__init__() + self.presenter = presenter + self.setWindowTitle("Python Help Window") + self.resize(800, 600) + + # Web browser widget + self.browser = QWebEngineView() + + # Determine initial URL + local_docs_base = os.environ.get("MANTID_LOCAL_DOCS_BASE") + if local_docs_base and os.path.isdir(local_docs_base): + index_path = os.path.join(local_docs_base, "index.html") + self.browser.setUrl(QUrl.fromLocalFile(index_path)) + else: + self.browser.setUrl(QUrl("https://docs.mantidproject.org/")) + + # Toolbar with navigation buttons + self.toolbar = QToolBar("Navigation") + self.addToolBar(self.toolbar) + + # Back button + back_button = QPushButton() + back_button.setIcon(QIcon.fromTheme("go-previous")) + back_button.setToolTip("Go Back") + back_button.clicked.connect(self.browser.back) + self.toolbar.addWidget(back_button) + + # Forward button + forward_button = QPushButton() + forward_button.setIcon(QIcon.fromTheme("go-next")) + forward_button.setToolTip("Go Forward") + forward_button.clicked.connect(self.browser.forward) + self.toolbar.addWidget(forward_button) + + # Home button + home_button = QPushButton() + home_button.setIcon(QIcon.fromTheme("go-home")) + home_button.setToolTip("Go Home") + home_button.clicked.connect(self.go_home) + self.toolbar.addWidget(home_button) + + # Reload button + reload_button = QPushButton() + reload_button.setIcon(QIcon.fromTheme("view-refresh")) + reload_button.setToolTip("Reload") + reload_button.clicked.connect(self.browser.reload) + self.toolbar.addWidget(reload_button) + + # Layout + layout = QVBoxLayout() + layout.addWidget(self.browser) + + container = QWidget() + container.setLayout(layout) + self.setCentralWidget(container) + + def go_home(self): + """Navigate to the home page.""" + self.browser.setUrl(QUrl("https://docs.mantidproject.org/")) + + def display(self): + """Show the help window.""" + self.show() + + def closeEvent(self, event): + """Handle the close event and notify the presenter.""" + self.presenter.on_close() + super().closeEvent(event) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index a2c396b5e105..1cb748107ed7 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -86,6 +86,8 @@ set(SRC_FILES src/PropertyHandler.cpp src/PropertyWidget.cpp src/PropertyWidgetFactory.cpp + src/PythonHelpBridge.cpp + src/PythonHelpWindow.cpp src/PythonRunner.cpp src/QtAlgorithmRunner.cpp src/QtJobRunner.cpp @@ -215,6 +217,8 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/PropertyWidget.h + inc/MantidQtWidgets/Common/PythonHelpBridge.h + inc/MantidQtWidgets/Common/PythonHelpWindow.h inc/MantidQtWidgets/Common/PythonRunner.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h inc/MantidQtWidgets/Common/QtJobRunner.h diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h index e8c8fe0d3a45..4b6dce8fc453 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/InterfaceManager.h @@ -138,6 +138,6 @@ class EXPORT_OPT_MANTIDQT_COMMON InterfaceManager { namespace { \ Mantid::Kernel::RegistrationHelper \ register_helpviewer(((MantidQt::API::InterfaceManager::registerHelpWindowFactory( \ - new Mantid::Kernel::Instantiator())), \ + new Mantid::Kernel::Instantiator())), \ 0)); \ } diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h index 1d503ff3dddb..9527d28f7714 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/MantidHelpWindow.h @@ -25,7 +25,7 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf Q_OBJECT public: - static bool helpWindowExists() { return !g_helpWindow.isNull(); } + static bool helpWindowExists(); MantidHelpWindow(const Qt::WindowFlags &flags = Qt::WindowFlags()); @@ -43,6 +43,11 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf void showCustomInterface(const QString &name, const QString &area = QString(), const QString §ion = QString()) override; +public slots: + /// Perform any clean up on main window shutdown + void shutdown() override; + void warning(const QString &msg); + private: void showHelp(const QString &url); void openWebpage(const QUrl &url); @@ -51,17 +56,11 @@ class EXPORT_OPT_MANTIDQT_COMMON MantidHelpWindow : public API::MantidHelpInterf std::string m_collectionFile; /// The window that renders the help information static QPointer g_helpWindow; - /// Whether this is the very first startup of the helpwindow. bool m_firstRun; - void findCollectionFile(std::string &binDir); + void findCollectionFile(const std::string &binDir); void determineFileLocs(); - -public slots: - /// Perform any clean up on main window shutdown - void shutdown() override; - void warning(const QString &msg); }; } // namespace MantidWidgets diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h new file mode 100644 index 000000000000..ea26e0dd8175 --- /dev/null +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h @@ -0,0 +1,10 @@ +#pragma once + +#include "DllOption.h" +#include + +class PythonHelpBridge { +public: + PythonHelpBridge(); + void showHelpPage(const std::string &relative_url); +}; diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h new file mode 100644 index 000000000000..acf5e0c13986 --- /dev/null +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpWindow.h @@ -0,0 +1,32 @@ +#pragma once + +#include "MantidQtWidgets/Common/DllOption.h" +#include "MantidQtWidgets/Common/MantidHelpInterface.h" +#include +#include +#include + +namespace MantidQt { +namespace MantidWidgets { + +class EXPORT_OPT_MANTIDQT_COMMON PythonHelpWindow : public MantidQt::API::MantidHelpInterface { +public: + PythonHelpWindow(); + void showPage(const std::string &url = std::string()) override; + void showPage(const QString &url) override; + void showPage(const QUrl &url) override; + void showAlgorithm(const std::string &name = std::string(), const int version = -1) override; + void showAlgorithm(const QString &name, const int version = -1) override; + void showConcept(const std::string &name) override; + void showConcept(const QString &name) override; + void showFitFunction(const std::string &name = std::string()) override; + void showFitFunction(const QString &name) override; + void showCustomInterface(const std::string &name = std::string(), const std::string &area = std::string(), + const std::string §ion = std::string()) override; + void showCustomInterface(const QString &name, const QString &area = QString(), + const QString §ion = QString()) override; + void shutdown() override; +}; + +} // namespace MantidWidgets +} // namespace MantidQt diff --git a/qt/widgets/common/src/InterfaceManager.cpp b/qt/widgets/common/src/InterfaceManager.cpp index d8e5d08899c5..abbadc961de9 100644 --- a/qt/widgets/common/src/InterfaceManager.cpp +++ b/qt/widgets/common/src/InterfaceManager.cpp @@ -14,6 +14,7 @@ #include "MantidQtWidgets/Common/MantidDesktopServices.h" #include "MantidQtWidgets/Common/MantidHelpWindow.h" #include "MantidQtWidgets/Common/PluginLibraries.h" +#include "MantidQtWidgets/Common/PythonHelpBridge.h" #include "MantidQtWidgets/Common/UserSubWindow.h" #include "MantidQtWidgets/Common/UserSubWindowFactory.h" @@ -23,7 +24,10 @@ #include "MantidKernel/Logger.h" #include +#include #include +#include +#include using namespace MantidQt::API; using Mantid::Kernel::AbstractInstantiator; @@ -154,7 +158,7 @@ UserSubWindow *InterfaceManager::createSubWindow(const QString &interface_name, g_log.debug() << "Created a specialised interface for " << iname << '\n'; // set the parent. Note - setParent without flags parameter resets the flags - // ie window becomes a child widget + // i.e. window becomes a child widget if (isWindow) { user_win->setParent(parent, user_win->windowFlags()); } else { @@ -233,6 +237,7 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { MantidHelpInterface *interface = this->m_helpViewer->createUnwrappedInstance(); if (!interface) { g_log.error("Error creating help window"); + return nullptr; } return interface; } @@ -240,27 +245,58 @@ MantidHelpInterface *InterfaceManager::createHelpWindow() const { void InterfaceManager::showHelpPage(const QString &url) { auto window = createHelpWindow(); - window->showPage(url); + if (window) + window->showPage(url); + else + MantidDesktopServices::openUrl(url); } void InterfaceManager::showAlgorithmHelp(const QString &name, const int version) { auto window = createHelpWindow(); - window->showAlgorithm(name, version); + if (window) + window->showAlgorithm(name, version); + else { + QString url("https://docs.mantidproject.org/algorithms/"); + url += name.isEmpty() ? "index.html" : name + (version > 0 ? "-v" + QString::number(version) + ".html" : ".html"); + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showConceptHelp(const QString &name) { auto window = createHelpWindow(); - window->showConcept(name); + if (window) + window->showConcept(name); + else { + QString url("https://docs.mantidproject.org/concepts/"); + url += name.isEmpty() ? "index.html" : name + ".html"; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showFitFunctionHelp(const QString &name) { auto window = createHelpWindow(); - window->showFitFunction(name); + if (window) + window->showFitFunction(name); + else { + QString url("https://docs.mantidproject.org/fitting/fitfunctions/"); + url += name.isEmpty() ? "index.html" : name + ".html"; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showCustomInterfaceHelp(const QString &name, const QString &area, const QString §ion) { auto window = createHelpWindow(); - window->showCustomInterface(name, area, section); + if (window) + window->showCustomInterface(name, area, section); + else { + QString url("https://docs.mantidproject.org/interfaces/"); + if (!area.isEmpty()) + url += area + "/"; + url += name.isEmpty() ? "index.html" : name + ".html"; + if (!section.isEmpty()) + url += "#" + section; + MantidDesktopServices::openUrl(url); + } } void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices::openUrl(url); } @@ -268,6 +304,7 @@ void InterfaceManager::showWebPage(const QString &url) { MantidDesktopServices:: void InterfaceManager::closeHelpWindow() { if (MantidHelpWindow::helpWindowExists()) { auto window = createHelpWindow(); - window->shutdown(); + if (window) + window->shutdown(); } } diff --git a/qt/widgets/common/src/MantidHelpWindow.cpp b/qt/widgets/common/src/MantidHelpWindow.cpp index 32c04ab157ed..a49ff98b4bfd 100644 --- a/qt/widgets/common/src/MantidHelpWindow.cpp +++ b/qt/widgets/common/src/MantidHelpWindow.cpp @@ -36,7 +36,9 @@ namespace MantidQt::MantidWidgets { using std::string; using namespace MantidQt::API; +#ifdef DOCS_QTHELP REGISTER_HELPWINDOW(MantidHelpWindow) +#endif namespace { /// static logger @@ -63,6 +65,8 @@ const QString HTML_BASE_PATH("/"); /// Page to display if nothing provided const QString DEFAULT_PAGENAME("index"); +bool MantidHelpWindow::helpWindowExists() { return !g_helpWindow.isNull(); } + /** * Default constructor shows the base index page. */ @@ -298,7 +302,7 @@ void MantidHelpWindow::shutdown() { * * @param binDir The location of the mantid executable. */ -void MantidHelpWindow::findCollectionFile(std::string &binDir) { +void MantidHelpWindow::findCollectionFile(const std::string &binDir) { // this being empty notes the feature being disabled m_collectionFile = ""; @@ -315,9 +319,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } // try where the builds will put it for a single configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -326,9 +330,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { } } // try where the builds will put it for a multi-configuration build - searchDir.cdUp(); + UNUSED_ARG(searchDir.cdUp()); if (searchDir.cd("docs")) { - searchDir.cd("qthelp"); + UNUSED_ARG(searchDir.cd("qthelp")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -339,9 +343,9 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try in windows/linux install location searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { @@ -351,10 +355,10 @@ void MantidHelpWindow::findCollectionFile(std::string &binDir) { // try a special place for mac/osx searchDir = QDir(QString::fromStdString(binDir)); - searchDir.cdUp(); - searchDir.cdUp(); - searchDir.cd("share"); - searchDir.cd("doc"); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cdUp()); + UNUSED_ARG(searchDir.cd("share")); + UNUSED_ARG(searchDir.cd("doc")); path = searchDir.absoluteFilePath(COLLECTION_FILE); g_log.debug() << "Trying \"" << path.toStdString() << "\"\n"; if (searchDir.exists(COLLECTION_FILE)) { diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp new file mode 100644 index 000000000000..bb1b0c8ef5c7 --- /dev/null +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -0,0 +1,33 @@ +#include "MantidQtWidgets/Common/PythonHelpBridge.h" +#include +#include +#include + +namespace { // anonymous +// name of the module to import the bridge +const std::string MOD_NAME("mantidqt.widgets.helpwindow.helpwindowbridge"); +// python::str version of the module +const boost::python::str MOD_NAME_PY(MOD_NAME); +} // namespace + +PythonHelpBridge::PythonHelpBridge() { + Py_Initialize(); + try { + boost::python::object main = boost::python::import("__main__"); + boost::python::object global = main.attr("__dict__"); + boost::python::import(MOD_NAME_PY); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + throw std::runtime_error("Failed to import '" + MOD_NAME + "' module."); + } +} + +void PythonHelpBridge::showHelpPage(const std::string &relative_url) { + try { + boost::python::object module = boost::python::import(MOD_NAME_PY); + module.attr("show_help_page")(relative_url); + } catch (boost::python::error_already_set &) { + PyErr_Print(); + throw std::runtime_error("Error calling show_help_page in Python."); + } +} diff --git a/qt/widgets/common/src/PythonHelpWindow.cpp b/qt/widgets/common/src/PythonHelpWindow.cpp new file mode 100644 index 000000000000..7504c9ad9fc7 --- /dev/null +++ b/qt/widgets/common/src/PythonHelpWindow.cpp @@ -0,0 +1,92 @@ +#include "MantidQtWidgets/Common/PythonHelpWindow.h" +#include "MantidKernel/RegistrationHelper.h" +#include "MantidQtWidgets/Common/InterfaceManager.h" +#include "MantidQtWidgets/Common/PythonHelpBridge.h" +#include +#include + +namespace MantidQt { +namespace MantidWidgets { + +#ifndef DOCS_QTHELP +REGISTER_HELPWINDOW(PythonHelpWindow) +#endif + +PythonHelpWindow::PythonHelpWindow() : MantidQt::API::MantidHelpInterface() {} + +void PythonHelpWindow::showPage(const std::string &url) { + PythonHelpBridge bridge; + bridge.showHelpPage(url.empty() ? "index.html" : url); +} + +void PythonHelpWindow::showPage(const QString &url) { + PythonHelpBridge bridge; + std::string page = url.isEmpty() ? "index.html" : url.toStdString(); + bridge.showHelpPage(page); +} + +void PythonHelpWindow::showPage(const QUrl &url) { + PythonHelpBridge bridge; + std::string page = url.isEmpty() ? "index.html" : url.toString().toStdString(); + bridge.showHelpPage(page); +} + +void PythonHelpWindow::showAlgorithm(const std::string &name, const int version) { + QString page = "algorithms/" + QString::fromStdString(name); + if (!name.empty() && version > 0) + page += "-v" + QString::number(version) + ".html"; + else if (!name.empty()) + page += ".html"; + else + page = "algorithms/index.html"; + showPage(page); +} + +void PythonHelpWindow::showAlgorithm(const QString &name, const int version) { + std::string n = name.toStdString(); + showAlgorithm(n, version); +} + +void PythonHelpWindow::showConcept(const std::string &name) { + QString page = name.empty() ? "concepts/index.html" : "concepts/" + QString::fromStdString(name) + ".html"; + showPage(page); +} + +void PythonHelpWindow::showConcept(const QString &name) { + std::string n = name.toStdString(); + showConcept(n); +} + +void PythonHelpWindow::showFitFunction(const std::string &name) { + QString page = name.empty() ? "fitting/fitfunctions/index.html" + : "fitting/fitfunctions/" + QString::fromStdString(name) + ".html"; + showPage(page); +} + +void PythonHelpWindow::showFitFunction(const QString &name) { + std::string n = name.toStdString(); + showFitFunction(n); +} + +void PythonHelpWindow::showCustomInterface(const std::string &name, const std::string &area, + const std::string §ion) { + QString areaPath = area.empty() ? "" : QString::fromStdString(area) + "/"; + QString page = "interfaces/" + areaPath + (name.empty() ? "index.html" : QString::fromStdString(name) + ".html"); + if (!section.empty()) + page += "#" + QString::fromStdString(section); + showPage(page); +} + +void PythonHelpWindow::showCustomInterface(const QString &name, const QString &area, const QString §ion) { + std::string n = name.toStdString(); + std::string a = area.toStdString(); + std::string s = section.toStdString(); + showCustomInterface(n, a, s); +} + +void PythonHelpWindow::shutdown() { + // no-op for python help window +} + +} // namespace MantidWidgets +} // namespace MantidQt From 9eb6c9c73c146d01d53faedae7155febc1f3b6b5 Mon Sep 17 00:00:00 2001 From: Darsh Date: Mon, 27 Jan 2025 10:42:55 -0500 Subject: [PATCH 27/28] Updates to CMakeLists.txt for cppcheck --- qt/widgets/common/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/qt/widgets/common/CMakeLists.txt b/qt/widgets/common/CMakeLists.txt index 1cb748107ed7..0c9929fd36c7 100644 --- a/qt/widgets/common/CMakeLists.txt +++ b/qt/widgets/common/CMakeLists.txt @@ -1,3 +1,5 @@ +option(DDOCS_QTHELP "If enabled add a target to build the qthelp documentation for qtassistant" ON) + set(SRC_FILES src/AddWorkspaceDialog.cpp src/AddWorkspaceMultiDialog.cpp @@ -161,6 +163,11 @@ set(SRC_FILES src/Python/QHashToDict.cpp ) +if(DDOCS_QTHELP STREQUAL "OFF") + list(APPEND SRC_FILES src/PythonHelpBridge.cpp) + list(APPEND SRC_FILES src/PythonHelpWindow.cpp) +endif() + set(QT5_MOC_FILES inc/MantidQtWidgets/Common/AddWorkspaceDialog.h inc/MantidQtWidgets/Common/AddWorkspaceMultiDialog.h @@ -217,8 +224,6 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/ProcessingAlgoWidget.h inc/MantidQtWidgets/Common/PropertyHandler.h inc/MantidQtWidgets/Common/PropertyWidget.h - inc/MantidQtWidgets/Common/PythonHelpBridge.h - inc/MantidQtWidgets/Common/PythonHelpWindow.h inc/MantidQtWidgets/Common/PythonRunner.h inc/MantidQtWidgets/Common/QtAlgorithmRunner.h inc/MantidQtWidgets/Common/QtJobRunner.h @@ -266,6 +271,11 @@ set(QT5_MOC_FILES inc/MantidQtWidgets/Common/QtPropertyBrowser/WorkspaceEditorFactory.h ) +if(DDOCS_QTHELP STREQUAL "OFF") + list(APPEND QT5_MOC_FILES inc/MantidQtWidgets/Common/PythonHelpBridge.h) + list(APPEND QT5_MOC_FILES inc/MantidQtWidgets/Common/PythonHelpWindow.h) +endif() + # Include files aren't required, but this makes them appear in Visual Studio set(QT5_INC_FILES ${QT5_MOC_FILES} From 7dfa4b4752c52484e0fe885f4d6263ba71de694a Mon Sep 17 00:00:00 2001 From: Darsh Date: Thu, 13 Feb 2025 15:33:24 -0500 Subject: [PATCH 28/28] Updates to make it all work --- .../workbench/workbench/app/main.py | 1 + .../widgets/helpwindow/helpwindowview.py | 2 +- .../MantidQtWidgets/Common/PythonHelpBridge.h | 16 ++++++- qt/widgets/common/src/AlgorithmDialog.cpp | 8 +++- qt/widgets/common/src/PythonHelpBridge.cpp | 42 +++++++++++++------ 5 files changed, 53 insertions(+), 16 deletions(-) diff --git a/qt/applications/workbench/workbench/app/main.py b/qt/applications/workbench/workbench/app/main.py index fa29cbdecd24..c9591866619f 100644 --- a/qt/applications/workbench/workbench/app/main.py +++ b/qt/applications/workbench/workbench/app/main.py @@ -9,6 +9,7 @@ import os from mantid import __version__ as mtd_version +from qtpy.QtWebEngineWidgets import QWebEngineView # noqa: F401 import warnings diff --git a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py index dbe9e9951ffe..99274df930c7 100644 --- a/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py +++ b/qt/python/mantidqt/mantidqt/widgets/helpwindow/helpwindowview.py @@ -1,6 +1,6 @@ import os -from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QToolBar, QPushButton, QWidget from qtpy.QtWebEngineWidgets import QWebEngineView +from qtpy.QtWidgets import QMainWindow, QVBoxLayout, QToolBar, QPushButton, QWidget from qtpy.QtCore import QUrl from qtpy.QtGui import QIcon diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h index ea26e0dd8175..2740d038fad1 100644 --- a/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h +++ b/qt/widgets/common/inc/MantidQtWidgets/Common/PythonHelpBridge.h @@ -1,10 +1,22 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2013 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + #pragma once -#include "DllOption.h" +#include "MantidQtWidgets/Common/DllOption.h" #include -class PythonHelpBridge { +namespace MantidQt { +namespace MantidWidgets { + +class EXPORT_OPT_MANTIDQT_COMMON PythonHelpBridge { public: PythonHelpBridge(); void showHelpPage(const std::string &relative_url); }; + +} // namespace MantidWidgets +} // namespace MantidQt diff --git a/qt/widgets/common/src/AlgorithmDialog.cpp b/qt/widgets/common/src/AlgorithmDialog.cpp index 564afbf8f6cd..5162597c0843 100644 --- a/qt/widgets/common/src/AlgorithmDialog.cpp +++ b/qt/widgets/common/src/AlgorithmDialog.cpp @@ -14,6 +14,7 @@ #include "MantidQtWidgets/Common/AlgorithmInputHistory.h" #include "MantidQtWidgets/Common/FilePropertyWidget.h" #include "MantidQtWidgets/Common/HelpWindow.h" +#include "MantidQtWidgets/Common/InterfaceManager.h" #include "MantidQtWidgets/Common/MantidWidget.h" #include "MantidQtWidgets/Common/PropertyWidget.h" @@ -707,11 +708,16 @@ void AlgorithmDialog::reject() { void AlgorithmDialog::helpClicked() { // determine the version to show int version(-1); // the latest version - if (m_algorithm) + if (m_algorithm) { version = m_algorithm->version(); + } +#ifndef DOCS_QTHELP + MantidQt::API::InterfaceManager().showAlgorithmHelp(m_algName, version); +#else // bring up the help window HelpWindow::showAlgorithm(m_algName, version); +#endif } //------------------------------------------------------------------------------------------------- diff --git a/qt/widgets/common/src/PythonHelpBridge.cpp b/qt/widgets/common/src/PythonHelpBridge.cpp index bb1b0c8ef5c7..7ecb9043dbf6 100644 --- a/qt/widgets/common/src/PythonHelpBridge.cpp +++ b/qt/widgets/common/src/PythonHelpBridge.cpp @@ -1,33 +1,51 @@ +// Mantid Repository : https://github.com/mantidproject/mantid +// +// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, +// NScD Oak Ridge National Laboratory, European Spallation Source, +// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS +// SPDX - License - Identifier: GPL - 3.0 + #include "MantidQtWidgets/Common/PythonHelpBridge.h" +#include #include #include #include -namespace { // anonymous -// name of the module to import the bridge +namespace { const std::string MOD_NAME("mantidqt.widgets.helpwindow.helpwindowbridge"); -// python::str version of the module const boost::python::str MOD_NAME_PY(MOD_NAME); + +boost::python::object getHelpWindowModule() { + static bool imported = false; + static boost::python::object module; + if (!imported) { + module = boost::python::import(MOD_NAME_PY); + imported = true; + } + return module; +} } // namespace +namespace MantidQt { +namespace MantidWidgets { + PythonHelpBridge::PythonHelpBridge() { - Py_Initialize(); - try { - boost::python::object main = boost::python::import("__main__"); - boost::python::object global = main.attr("__dict__"); - boost::python::import(MOD_NAME_PY); - } catch (boost::python::error_already_set &) { - PyErr_Print(); - throw std::runtime_error("Failed to import '" + MOD_NAME + "' module."); + if (!Py_IsInitialized()) { + Py_Initialize(); } } void PythonHelpBridge::showHelpPage(const std::string &relative_url) { + PyGILState_STATE gstate = PyGILState_Ensure(); try { - boost::python::object module = boost::python::import(MOD_NAME_PY); + boost::python::object module = getHelpWindowModule(); module.attr("show_help_page")(relative_url); + } catch (boost::python::error_already_set &) { PyErr_Print(); + PyGILState_Release(gstate); throw std::runtime_error("Error calling show_help_page in Python."); } + PyGILState_Release(gstate); } +} // namespace MantidWidgets +} // namespace MantidQt