From f4b018bcf6ae2bd81e3fb2f0802c6ee32cad9555 Mon Sep 17 00:00:00 2001 From: Martin Rotter Date: Thu, 23 Nov 2023 08:14:00 +0100 Subject: [PATCH] working on unifications of context menus in web viewers --- localization/rssguard_en.ts | 52 +++------ src/librssguard/CMakeLists.txt | 1 + .../qtextbrowser/textbrowserviewer.cpp | 78 +++---------- .../qtextbrowser/textbrowserviewer.h | 4 +- .../webviewers/webengine/webengineviewer.cpp | 85 ++++---------- .../webviewers/webengine/webengineviewer.h | 4 +- src/librssguard/gui/webviewers/webviewer.cpp | 110 ++++++++++++++++++ src/librssguard/gui/webviewers/webviewer.h | 29 ++++- 8 files changed, 200 insertions(+), 163 deletions(-) create mode 100644 src/librssguard/gui/webviewers/webviewer.cpp diff --git a/localization/rssguard_en.ts b/localization/rssguard_en.ts index 5ea9502bc..1a5a5bdb1 100644 --- a/localization/rssguard_en.ts +++ b/localization/rssguard_en.ts @@ -5859,6 +5859,21 @@ List of supported readers: not a Sitemap + + + Open with external tool + + + + + Open in external browser + + + + + Open link as audio/video + + Readability @@ -8026,25 +8041,15 @@ Unread news: %2 - + Enable external resources - - Open in external browser - - - - + Download - - - Open with external tool - - TimeSpinBox @@ -8529,29 +8534,6 @@ Last login on: %4 - - WebEngineViewer - - - Open link in external browser - - - - - Open link as audio/video - - - - - Open with external tool - - - - - No external tools activated - - - WebFactory diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt index bde335375..652a32654 100644 --- a/src/librssguard/CMakeLists.txt +++ b/src/librssguard/CMakeLists.txt @@ -205,6 +205,7 @@ set(SOURCES gui/toolbars/toolbareditor.h gui/webbrowser.cpp gui/webbrowser.h + gui/webviewers/webviewer.cpp gui/webviewers/webviewer.h miscellaneous/application.cpp miscellaneous/application.h diff --git a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp index 91f2743cd..a8539ee14 100644 --- a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp +++ b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.cpp @@ -365,69 +365,33 @@ void TextBrowserViewer::contextMenuEvent(QContextMenuEvent* event) { return; } + /* + connect(menu, &QMenu::aboutToHide, this, [menu] { + menu->deleteLater(); + });*/ + if (m_actionEnableResources.isNull()) { m_actionEnableResources.reset(new QAction(qApp->icons()->fromTheme(QSL("viewimage"), QSL("image-x-generic")), tr("Enable external resources"), this)); - m_actionOpenExternalBrowser.reset(new QAction(qApp->icons()->fromTheme(QSL("document-open")), - tr("Open in external browser"), - this)); m_actionDownloadLink.reset(new QAction(qApp->icons()->fromTheme(QSL("download")), tr("Download"), this)); m_actionEnableResources.data()->setCheckable(true); m_actionEnableResources.data()->setChecked(resourcesEnabled()); - connect(m_actionOpenExternalBrowser.data(), - &QAction::triggered, - this, - &TextBrowserViewer::openLinkInExternalBrowser); connect(m_actionDownloadLink.data(), &QAction::triggered, this, &TextBrowserViewer::downloadLink); connect(m_actionEnableResources.data(), &QAction::toggled, this, &TextBrowserViewer::enableResources); } menu->addAction(m_actionEnableResources.data()); - menu->addAction(m_actionOpenExternalBrowser.data()); menu->addAction(m_actionDownloadLink.data()); auto anchor = anchorAt(event->pos()); m_lastContextMenuPos = event->pos(); - m_actionOpenExternalBrowser.data()->setEnabled(!anchor.isEmpty()); m_actionDownloadLink.data()->setEnabled(!anchor.isEmpty()); - if (!anchor.isEmpty()) { - QFileIconProvider icon_provider; - QMenu* menu_ext_tools = new QMenu(tr("Open with external tool"), menu); - auto tools = ExternalTool::toolsFromSettings(); - - menu_ext_tools->setIcon(qApp->icons()->fromTheme(QSL("document-open"))); - - for (const ExternalTool& tool : std::as_const(tools)) { - QAction* act_tool = new QAction(QFileInfo(tool.executable()).fileName(), menu_ext_tools); - - act_tool->setIcon(icon_provider.icon(QFileInfo(tool.executable()))); - act_tool->setToolTip(tool.executable()); - act_tool->setData(QVariant::fromValue(tool)); - menu_ext_tools->addAction(act_tool); - - connect(act_tool, &QAction::triggered, this, [act_tool, anchor]() { - act_tool->data().value().run(anchor); - }); - } - - if (menu_ext_tools->actions().isEmpty()) { - QAction* act_not_tools = new QAction("No external tools activated"); - - act_not_tools->setEnabled(false); - menu_ext_tools->addAction(act_not_tools); - } - - menu->addMenu(menu_ext_tools); - } - - connect(menu, &QMenu::aboutToHide, this, [menu] { - menu->deleteLater(); - }); + processContextMenu(menu, event); menu->popup(event->globalPos()); } @@ -449,24 +413,6 @@ void TextBrowserViewer::enableResources(bool enable) { setResourcesEnabled(enable); } -void TextBrowserViewer::openLinkInExternalBrowser() { - auto url = QUrl(anchorAt(m_lastContextMenuPos)); - - if (url.isValid()) { - const QUrl resolved_url = (m_currentUrl.isValid() && url.isRelative()) ? m_currentUrl.resolved(url) : url; - - qApp->web()->openUrlInExternalBrowser(resolved_url.toString()); - - if (qApp->settings() - ->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally)) - .toBool()) { - QTimer::singleShot(1000, qApp, []() { - qApp->mainForm()->display(); - }); - } - } -} - void TextBrowserViewer::downloadLink() { auto url = QUrl(anchorAt(m_lastContextMenuPos)); @@ -644,3 +590,15 @@ bool TextBrowserViewer::resourcesEnabled() const { void TextBrowserViewer::setResourcesEnabled(bool enabled) { m_resourcesEnabled = enabled; } + +ContextMenuData TextBrowserViewer::provideContextMenuData(QContextMenuEvent* event) const { + ContextMenuData c; + + QString anchor = anchorAt(event->pos()); + + if (!anchor.isEmpty()) { + c.m_linkUrl = anchor; + } + + return c; +} diff --git a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h index 93badca3a..f613e888a 100644 --- a/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h +++ b/src/librssguard/gui/webviewers/qtextbrowser/textbrowserviewer.h @@ -63,13 +63,14 @@ class TextBrowserViewer : public QTextBrowser, public WebViewer { void setResourcesEnabled(bool enabled); protected: + virtual ContextMenuData provideContextMenuData(QContextMenuEvent* event) const; + virtual void contextMenuEvent(QContextMenuEvent* event); virtual void resizeEvent(QResizeEvent* event); virtual void wheelEvent(QWheelEvent* event); private slots: void enableResources(bool enable); - void openLinkInExternalBrowser(); void downloadLink(); void onAnchorClicked(const QUrl& url); void reloadHtmlDelayed(); @@ -112,7 +113,6 @@ class TextBrowserViewer : public QTextBrowser, public WebViewer { QFont m_baseFont; qreal m_zoomFactor = 1.0; QScopedPointer m_actionEnableResources; - QScopedPointer m_actionOpenExternalBrowser; QScopedPointer m_actionDownloadLink; QScopedPointer m_document; QPoint m_lastContextMenuPos; diff --git a/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp b/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp index 513d4f27a..e93409ff1 100644 --- a/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp +++ b/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp @@ -78,74 +78,18 @@ void WebEngineViewer::contextMenuEvent(QContextMenuEvent* event) { #if QT_VERSION_MAJOR == 6 QMenu* menu = createStandardContextMenu(); - auto* menu_pointer = lastContextMenuRequest(); - QWebEngineContextMenuRequest& menu_data = *menu_pointer; #else QMenu* menu = page()->createStandardContextMenu(); - QWebEngineContextMenuData menu_data = page()->contextMenuData(); #endif - if (menu_data.linkUrl().isValid()) { - QString link_url = menu_data.linkUrl().toString(); - - // Add option to open link in external viewe - menu->addAction(qApp->icons()->fromTheme(QSL("document-open")), tr("Open link in external browser"), [link_url]() { - qApp->web()->openUrlInExternalBrowser(link_url); - - if (qApp->settings() - ->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally)) - .toBool()) { - QTimer::singleShot(1000, qApp, []() { - qApp->mainForm()->display(); - }); - } - }); - - menu->addAction(qApp->icons()->fromTheme(QSL("player_play"), QSL("media-playback-start")), - tr("Open link as audio/video"), - [link_url]() { - qApp->mainForm()->tabWidget()->addMediaPlayer(link_url, true); - }); - } - - if (menu_data.mediaUrl().isValid() || menu_data.linkUrl().isValid()) { - QString media_link = - menu_data.mediaUrl().isValid() ? menu_data.mediaUrl().toString() : menu_data.linkUrl().toString(); - QFileIconProvider icon_provider; - QMenu* menu_ext_tools = new QMenu(tr("Open with external tool"), menu); - auto tools = ExternalTool::toolsFromSettings(); - - menu_ext_tools->setIcon(qApp->icons()->fromTheme(QSL("document-open"))); - - for (const ExternalTool& tool : std::as_const(tools)) { - QAction* act_tool = new QAction(QFileInfo(tool.executable()).fileName(), menu_ext_tools); - - act_tool->setIcon(icon_provider.icon(QFileInfo(tool.executable()))); - act_tool->setToolTip(tool.executable()); - act_tool->setData(QVariant::fromValue(tool)); - menu_ext_tools->addAction(act_tool); - - connect(act_tool, &QAction::triggered, this, [this, act_tool, media_link]() { - openUrlWithExternalTool(act_tool->data().value(), media_link); - }); - } - - if (menu_ext_tools->actions().isEmpty()) { - QAction* act_not_tools = new QAction(tr("No external tools activated")); - - act_not_tools->setEnabled(false); - menu_ext_tools->addAction(act_not_tools); - } - - menu->addMenu(menu_ext_tools); - } - menu->addAction(qApp->web()->adBlock()->adBlockIcon()); menu->addAction(qApp->web()->engineSettingsAction()); const QPoint pos = event->globalPos(); QPoint p(pos.x(), pos.y() + 1); + processContextMenu(menu, event); + menu->popup(p); } @@ -160,10 +104,6 @@ void WebEngineViewer::openUrlWithExternalTool(ExternalTool tool, const QString& tool.run(target_url); } -RootItem* WebEngineViewer::root() const { - return m_root; -} - void WebEngineViewer::bindToBrowser(WebBrowser* browser) { m_browser = browser; @@ -258,3 +198,24 @@ QString WebEngineViewer::html() const { QUrl WebEngineViewer::url() const { return QWebEngineView::url(); } + +ContextMenuData WebEngineViewer::provideContextMenuData(QContextMenuEvent* event) const { +#if QT_VERSION_MAJOR == 6 + auto* menu_pointer = lastContextMenuRequest(); + QWebEngineContextMenuRequest& menu_data = *menu_pointer; +#else + QWebEngineContextMenuData menu_data = page()->contextMenuData(); +#endif + + ContextMenuData c; + + if (menu_data.mediaUrl().isValid()) { + c.m_mediaUrl = menu_data.linkUrl(); + } + + if (menu_data.linkUrl().isValid()) { + c.m_linkUrl = menu_data.linkUrl(); + } + + return c; +} diff --git a/src/librssguard/gui/webviewers/webengine/webengineviewer.h b/src/librssguard/gui/webviewers/webengine/webengineviewer.h index 93a71975c..022c7ab2f 100644 --- a/src/librssguard/gui/webviewers/webengine/webengineviewer.h +++ b/src/librssguard/gui/webviewers/webengine/webengineviewer.h @@ -21,8 +21,6 @@ class WebEngineViewer : public QWebEngineView, public WebViewer { public: explicit WebEngineViewer(QWidget* parent = nullptr); - RootItem* root() const; - public: virtual void loadMessages(const QList& messages, RootItem* root); virtual void bindToBrowser(WebBrowser* browser); @@ -51,6 +49,8 @@ class WebEngineViewer : public QWebEngineView, public WebViewer { void closeWindowRequested(); protected: + virtual ContextMenuData provideContextMenuData(QContextMenuEvent* event) const; + virtual QWebEngineView* createWindow(QWebEnginePage::WebWindowType type); virtual void contextMenuEvent(QContextMenuEvent* event); virtual bool event(QEvent* event); diff --git a/src/librssguard/gui/webviewers/webviewer.cpp b/src/librssguard/gui/webviewers/webviewer.cpp new file mode 100644 index 000000000..37ce81a69 --- /dev/null +++ b/src/librssguard/gui/webviewers/webviewer.cpp @@ -0,0 +1,110 @@ +// For license of this file, see /LICENSE.md. + +#include "gui/webviewers/webviewer.h" + +#include "gui/dialogs/formmain.h" +#include "miscellaneous/externaltool.h" +#include "miscellaneous/iconfactory.h" +#include "miscellaneous/settings.h" +#include "network-web/webfactory.h" + +#include +#include + +WebViewer::WebViewer() {} + +WebViewer::~WebViewer() {} + +void WebViewer::processContextMenu(QMenu* specific_menu, QContextMenuEvent* event) { + // Setup the menu. + m_contextMenuData = provideContextMenuData(event); + specific_menu->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose, true); + initializeCommonMenuItems(); + + // Add common items. + specific_menu->addSeparator(); + specific_menu->addAction(m_actionOpenExternalBrowser.data()); + specific_menu->addAction(m_actionPlayLink.data()); + + m_actionOpenExternalBrowser.data()->setEnabled(m_contextMenuData.m_linkUrl.isValid()); + m_actionPlayLink.data()->setEnabled(m_contextMenuData.m_linkUrl.isValid()); + + if (m_contextMenuData.m_linkUrl.isValid()) { + QFileIconProvider icon_provider; + QMenu* menu_ext_tools = new QMenu(QObject::tr("Open with external tool"), specific_menu); + auto tools = ExternalTool::toolsFromSettings(); + + menu_ext_tools->setIcon(qApp->icons()->fromTheme(QSL("document-open"))); + + for (const ExternalTool& tool : std::as_const(tools)) { + QAction* act_tool = new QAction(QFileInfo(tool.executable()).fileName(), menu_ext_tools); + + act_tool->setIcon(icon_provider.icon(QFileInfo(tool.executable()))); + act_tool->setToolTip(tool.executable()); + act_tool->setData(QVariant::fromValue(tool)); + menu_ext_tools->addAction(act_tool); + + QObject::connect(act_tool, &QAction::triggered, act_tool, [this, act_tool]() { + act_tool->data().value().run(m_contextMenuData.m_linkUrl.toString()); + }); + } + + if (menu_ext_tools->actions().isEmpty()) { + QAction* act_not_tools = new QAction("No external tools activated"); + + act_not_tools->setEnabled(false); + menu_ext_tools->addAction(act_not_tools); + } + + specific_menu->addMenu(menu_ext_tools); + } +} + +void WebViewer::playClickedLinkAsMedia() { + auto context_url = m_contextMenuData.m_linkUrl; + + if (context_url.isValid()) { + qApp->mainForm()->tabWidget()->addMediaPlayer(context_url.toString(), true); + } +} + +void WebViewer::openClickedLinkInExternalBrowser() { + auto context_url = m_contextMenuData.m_linkUrl; + + if (context_url.isValid()) { + const QUrl resolved_url = (url().isValid() && context_url.isRelative()) ? url().resolved(context_url) : context_url; + + qApp->web()->openUrlInExternalBrowser(resolved_url.toString()); + + if (qApp->settings() + ->value(GROUP(Messages), SETTING(Messages::BringAppToFrontAfterMessageOpenedExternally)) + .toBool()) { + QTimer::singleShot(1000, qApp, []() { + qApp->mainForm()->display(); + }); + } + } +} + +void WebViewer::initializeCommonMenuItems() { + if (!m_actionOpenExternalBrowser.isNull()) { + return; + } + + m_actionOpenExternalBrowser.reset(new QAction(qApp->icons()->fromTheme(QSL("document-open")), + QObject::tr("Open in external browser"))); + + m_actionPlayLink.reset(new QAction(qApp->icons()->fromTheme(QSL("player_play"), QSL("media-playback-start")), + QObject::tr("Open link as audio/video"))); + + QObject::connect(m_actionOpenExternalBrowser.data(), + &QAction::triggered, + m_actionOpenExternalBrowser.data(), + [this]() { + openClickedLinkInExternalBrowser(); + }); + + QObject::connect(m_actionPlayLink.data(), &QAction::triggered, m_actionPlayLink.data(), [this]() { + playClickedLinkAsMedia(); + }); +} diff --git a/src/librssguard/gui/webviewers/webviewer.h b/src/librssguard/gui/webviewers/webviewer.h index dc1ba2eaf..74a4795c0 100644 --- a/src/librssguard/gui/webviewers/webviewer.h +++ b/src/librssguard/gui/webviewers/webviewer.h @@ -1,3 +1,5 @@ +// For license of this file, see /LICENSE.md. + #ifndef WEBVIEWER_H #define WEBVIEWER_H @@ -5,8 +7,12 @@ #include "definitions/definitions.h" +#include #include +class QMenu; +class QContextMenuEvent; + class WebBrowser; class RootItem; @@ -15,9 +21,15 @@ struct PreparedHtml { QUrl m_baseUrl; }; +struct ContextMenuData { + QUrl m_linkUrl; + QUrl m_mediaUrl; +}; + // Interface for web/article viewers. class WebViewer { public: + WebViewer(); virtual ~WebViewer(); // Performs necessary steps to make viewer work with browser. @@ -68,6 +80,11 @@ class WebViewer { virtual qreal zoomFactor() const = 0; virtual void setZoomFactor(qreal zoom_factor) = 0; + protected: + void processContextMenu(QMenu* specific_menu, QContextMenuEvent* event); + + virtual ContextMenuData provideContextMenuData(QContextMenuEvent* event) const = 0; + signals: virtual void pageTitleChanged(const QString& new_title) = 0; virtual void pageUrlChanged(const QUrl& url) = 0; @@ -78,12 +95,20 @@ class WebViewer { virtual void loadingFinished(bool success) = 0; virtual void newWindowRequested(WebViewer* viewer) = 0; virtual void closeWindowRequested() = 0; + + private: + void playClickedLinkAsMedia(); + void openClickedLinkInExternalBrowser(); + void initializeCommonMenuItems(); + + private: + QScopedPointer m_actionOpenExternalBrowser; + QScopedPointer m_actionPlayLink; + ContextMenuData m_contextMenuData; }; Q_DECLARE_INTERFACE(WebViewer, "WebViewer") -inline WebViewer::~WebViewer() {} - inline void WebViewer::zoomIn() { setZoomFactor(zoomFactor() + double(ZOOM_FACTOR_STEP)); }