summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorValentin Fokin <fokinv@inf.u-szeged.hu>2017-11-21 13:39:26 +0100
committerPeter Varga <pvarga@inf.u-szeged.hu>2018-02-02 07:43:03 +0000
commita66db09c6efe0d4dcc6d6a3cc93a000207da2175 (patch)
tree55104bb1ac6c8f61df869e87affc095ff4c6080c /src
parent7c8c0414620cd3cb350e77cd88f83f83237eefa3 (diff)
Make default context menus look more like chrome's one
- Implement EditFlags in ContextMenuData - Unify Quick and Widget default context menus - Add workaround for QTBUG-65044 - Update the SimpleBrowser example and its documentation [ChangeLog][QtWebEngine][QtWebEngineWidgets] Unify Quick and Widget default context menus Task-number: QTBUG-62414 Change-Id: I16a380f9f17e160497dfb8ac9c172341eb28c6c8 Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/core/core_chromium.pri2
-rw-r--r--src/core/render_view_context_menu_qt.cpp224
-rw-r--r--src/core/render_view_context_menu_qt.h120
-rw-r--r--src/core/web_contents_adapter_client.h24
-rw-r--r--src/core/web_contents_view_qt.cpp12
-rw-r--r--src/webengine/api/qquickwebengineview.cpp325
-rw-r--r--src/webengine/api/qquickwebengineview_p.h2
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h19
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp298
-rw-r--r--src/webenginewidgets/api/qwebenginepage.h2
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h17
11 files changed, 822 insertions, 223 deletions
diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri
index 7a7e3ab02..08552800d 100644
--- a/src/core/core_chromium.pri
+++ b/src/core/core_chromium.pri
@@ -79,6 +79,7 @@ SOURCES = \
qrc_protocol_handler_qt.cpp \
quota_permission_context_qt.cpp \
quota_permission_controller.cpp \
+ render_view_context_menu_qt.cpp \
render_view_observer_host_qt.cpp \
render_widget_host_view_qt.cpp \
renderer/content_renderer_client_qt.cpp \
@@ -161,6 +162,7 @@ HEADERS = \
quota_permission_context_qt.h \
quota_permission_controller.h \
quota_permission_controller_p.h \
+ render_view_context_menu_qt.h \
render_view_observer_host_qt.h \
render_widget_host_view_qt.h \
render_widget_host_view_qt_delegate.h \
diff --git a/src/core/render_view_context_menu_qt.cpp b/src/core/render_view_context_menu_qt.cpp
new file mode 100644
index 000000000..4e182973c
--- /dev/null
+++ b/src/core/render_view_context_menu_qt.cpp
@@ -0,0 +1,224 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/QCoreApplication>
+#include "render_view_context_menu_qt.h"
+
+namespace QtWebEngineCore {
+
+ const QString RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem menuItem) {
+ Q_ASSERT(menuItem <= ContextMenuItem::ViewSource);
+ static const char *names[ContextMenuItem::ViewSource + 1] = {
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Back"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Forward"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Reload"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Cut"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Copy"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Paste"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Undo"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Redo"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Select all"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Paste and match style"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Open link in new window"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Open link in new tab"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Copy link address"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Save link"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Copy image"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Copy image address"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Save image"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Copy media address"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Show controls"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Loop"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Save media"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Inspect"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Exit full screen"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "Save page"),
+ QT_TRANSLATE_NOOP("RenderViewContextMenuQt", "View page source")
+ };
+ return QCoreApplication::translate("RenderViewContextMenuQt", qUtf8Printable(names[menuItem]));
+ }
+
+ RenderViewContextMenuQt::RenderViewContextMenuQt(const WebEngineContextMenuData &data)
+ : m_contextData(data)
+ {
+ }
+
+ void RenderViewContextMenuQt::initMenu()
+ {
+ if (isFullScreenMode()) {
+ appendExitFullscreenItem();
+ appendSeparatorItem();
+ }
+
+ if (m_contextData.isEditable() && !m_contextData.spellCheckerSuggestions().isEmpty()) {
+ appendSpellingSuggestionItems();
+ appendSeparatorItem();
+ }
+
+ if (m_contextData.linkText().isEmpty() && !m_contextData.linkUrl().isValid() && !m_contextData.mediaUrl().isValid()) {
+ if (m_contextData.isEditable())
+ appendEditableItems();
+ else if (!m_contextData.selectedText().isEmpty())
+ appendCopyItem();
+ else
+ appendPageItems();
+ }
+
+ if (m_contextData.linkUrl().isValid() || !m_contextData.unfilteredLinkUrl().isEmpty() || !m_contextData.linkUrl().isEmpty())
+ appendLinkItems();
+
+ if (m_contextData.mediaUrl().isValid()) {
+ switch (m_contextData.mediaType()) {
+ case WebEngineContextMenuData::MediaTypeImage:
+ appendSeparatorItem();
+ appendImageItems();
+ break;
+ case WebEngineContextMenuData::MediaTypeCanvas:
+ Q_UNREACHABLE(); // mediaUrl is invalid for canvases
+ break;
+ case WebEngineContextMenuData::MediaTypeAudio:
+ case WebEngineContextMenuData::MediaTypeVideo:
+ appendSeparatorItem();
+ appendMediaItems();
+ break;
+ default:
+ break;
+ }
+ } else if (m_contextData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) {
+ appendSeparatorItem();
+ appendCanvasItems();
+ }
+
+ if (canViewSource() || hasInspector()) {
+ appendSeparatorItem();
+ appendDeveloperItems();
+ }
+ }
+
+ void RenderViewContextMenuQt::appendCanvasItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::DownloadImageToDisk);
+ addMenuItem(RenderViewContextMenuQt::CopyImageToClipboard);
+ }
+
+ void RenderViewContextMenuQt::appendCopyItem()
+ {
+ addMenuItem(RenderViewContextMenuQt::Copy);
+ }
+
+ void RenderViewContextMenuQt::appendDeveloperItems()
+ {
+ if (canViewSource())
+ addMenuItem(RenderViewContextMenuQt::ViewSource);
+ if (hasInspector())
+ addMenuItem(RenderViewContextMenuQt::InspectElement);
+ }
+
+ void RenderViewContextMenuQt::appendEditableItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::Undo);
+ addMenuItem(RenderViewContextMenuQt::Redo);
+ appendSeparatorItem();
+ addMenuItem(RenderViewContextMenuQt::Cut);
+ addMenuItem(RenderViewContextMenuQt::Copy);
+ addMenuItem(RenderViewContextMenuQt::Paste);
+ if (m_contextData.misspelledWord().isEmpty()) {
+ addMenuItem(RenderViewContextMenuQt::PasteAndMatchStyle);
+ addMenuItem(RenderViewContextMenuQt::SelectAll);
+ }
+ }
+
+ void RenderViewContextMenuQt::appendExitFullscreenItem()
+ {
+ addMenuItem(RenderViewContextMenuQt::ExitFullScreen);
+ }
+
+ void RenderViewContextMenuQt::appendImageItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::DownloadImageToDisk);
+ addMenuItem(RenderViewContextMenuQt::CopyImageToClipboard);
+ addMenuItem(RenderViewContextMenuQt::CopyImageUrlToClipboard);
+ }
+
+ void RenderViewContextMenuQt::appendLinkItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::OpenLinkInNewTab);
+ addMenuItem(RenderViewContextMenuQt::OpenLinkInNewWindow);
+ appendSeparatorItem();
+ addMenuItem(RenderViewContextMenuQt::DownloadLinkToDisk);
+ addMenuItem(RenderViewContextMenuQt::CopyLinkToClipboard);
+ }
+
+ void RenderViewContextMenuQt::appendMediaItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::ToggleMediaLoop);
+ if (m_contextData.mediaFlags() & QtWebEngineCore::WebEngineContextMenuData::MediaCanToggleControls)
+ addMenuItem(RenderViewContextMenuQt::ToggleMediaControls);
+ addMenuItem(RenderViewContextMenuQt::DownloadMediaToDisk);
+ addMenuItem(RenderViewContextMenuQt::CopyMediaUrlToClipboard);
+ }
+
+ void RenderViewContextMenuQt::appendPageItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::Back);
+ addMenuItem(RenderViewContextMenuQt::Forward);
+ addMenuItem(RenderViewContextMenuQt::Reload);
+ appendSeparatorItem();
+ addMenuItem(RenderViewContextMenuQt::SavePage);
+ }
+
+ void RenderViewContextMenuQt::appendSpellingSuggestionItems()
+ {
+ addMenuItem(RenderViewContextMenuQt::SpellingSuggestions);
+ }
+
+ void RenderViewContextMenuQt::appendSeparatorItem()
+ {
+ addMenuItem(RenderViewContextMenuQt::Separator);
+ }
+
+ bool RenderViewContextMenuQt::canViewSource()
+ {
+ return m_contextData.linkText().isEmpty()
+ && !m_contextData.linkUrl().isValid()
+ && !m_contextData.mediaUrl().isValid()
+ && !m_contextData.isEditable()
+ && m_contextData.selectedText().isEmpty();
+ }
+}
diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h
new file mode 100644
index 000000000..1694f66e6
--- /dev/null
+++ b/src/core/render_view_context_menu_qt.h
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef RENDER_VIEW_CONTEXT_MENU_QT_H
+#define RENDER_VIEW_CONTEXT_MENU_QT_H
+
+#include "web_contents_adapter_client.h"
+
+namespace QtWebEngineCore {
+
+class QWEBENGINE_EXPORT RenderViewContextMenuQt
+{
+public:
+ enum ContextMenuItem {
+ Back = 0,
+ Forward,
+ Reload,
+
+ Cut,
+ Copy,
+ Paste,
+
+ Undo,
+ Redo,
+ SelectAll,
+
+ PasteAndMatchStyle,
+
+ OpenLinkInNewWindow,
+ OpenLinkInNewTab,
+ CopyLinkToClipboard,
+ DownloadLinkToDisk,
+
+ CopyImageToClipboard,
+ CopyImageUrlToClipboard,
+ DownloadImageToDisk,
+
+ CopyMediaUrlToClipboard,
+ ToggleMediaControls,
+ ToggleMediaLoop,
+ DownloadMediaToDisk,
+
+ InspectElement,
+ ExitFullScreen,
+ SavePage,
+ ViewSource,
+
+ SpellingSuggestions,
+
+ Separator
+ };
+
+ static const QString getMenuItemName(RenderViewContextMenuQt::ContextMenuItem menuItem);
+
+ RenderViewContextMenuQt(const WebEngineContextMenuData &data);
+ void initMenu();
+
+protected:
+ virtual bool hasInspector() = 0;
+ virtual bool isFullScreenMode() = 0;
+
+ virtual void addMenuItem(ContextMenuItem menuItem) = 0;
+ virtual bool isMenuItemEnabled(ContextMenuItem menuItem) = 0;
+
+ const WebEngineContextMenuData &m_contextData;
+
+private:
+ void appendCanvasItems();
+ void appendCopyItem();
+ void appendEditableItems();
+ void appendExitFullscreenItem();
+ void appendDeveloperItems();
+ void appendImageItems();
+ void appendLinkItems();
+ void appendMediaItems();
+ void appendPageItems();
+ void appendSpellingSuggestionItems();
+ void appendSeparatorItem();
+ bool canViewSource();
+};
+
+}
+
+#endif // RENDER_VIEW_CONTEXT_MENU_QT_H
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index d6de9dfe6..dfb2dddcc 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -95,6 +95,7 @@ public:
, isSpellCheckerEnabled(false)
, mediaType(0)
, mediaFlags(0)
+ , editFlags(0)
{
}
bool hasImageContent;
@@ -102,6 +103,7 @@ public:
bool isSpellCheckerEnabled;
uint mediaType;
uint mediaFlags;
+ uint editFlags;
QPoint pos;
QUrl linkUrl;
QUrl unfilteredLinkUrl;
@@ -155,6 +157,20 @@ public:
MediaCanRotate = 0x200,
};
+ // Must match blink::WebContextMenuData::EditFlags:
+ enum EditFlags {
+ CanDoNone = 0x0,
+ CanUndo = 0x1,
+ CanRedo = 0x2,
+ CanCut = 0x4,
+ CanCopy = 0x8,
+ CanPaste = 0x10,
+ CanDelete = 0x20,
+ CanSelectAll = 0x40,
+ CanTranslate = 0x80,
+ CanEditRichly = 0x100,
+ };
+
WebEngineContextMenuData():d(new WebEngineContextMenuSharedData) {
}
@@ -230,6 +246,14 @@ public:
return MediaFlags(d->mediaFlags);
}
+ void setEditFlags(EditFlags flags) {
+ d->editFlags = flags;
+ }
+
+ EditFlags editFlags() const {
+ return EditFlags(d->editFlags);
+ }
+
void setSuggestedFileName(const QString &filename) {
d->suggestedFileName = filename;
}
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index 28f202e24..0ad3c1c38 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -158,6 +158,17 @@ ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaControls, blink::WebContextMen
ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanPrint, blink::WebContextMenuData::kMediaCanPrint)
ASSERT_ENUMS_MATCH(WebEngineContextMenuData::MediaCanRotate, blink::WebContextMenuData::kMediaCanRotate)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDoNone, blink::WebContextMenuData::kCanDoNone)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanUndo, blink::WebContextMenuData::kCanUndo)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanRedo, blink::WebContextMenuData::kCanRedo)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCut, blink::WebContextMenuData::kCanCut)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanCopy, blink::WebContextMenuData::kCanCopy)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanPaste, blink::WebContextMenuData::kCanPaste)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanDelete, blink::WebContextMenuData::kCanDelete)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanSelectAll, blink::WebContextMenuData::kCanSelectAll)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanTranslate, blink::WebContextMenuData::kCanTranslate)
+ASSERT_ENUMS_MATCH(WebEngineContextMenuData::CanEditRichly, blink::WebContextMenuData::kCanEditRichly)
+
static inline WebEngineContextMenuData fromParams(const content::ContextMenuParams &params)
{
WebEngineContextMenuData ret;
@@ -170,6 +181,7 @@ static inline WebEngineContextMenuData fromParams(const content::ContextMenuPara
ret.setMediaType((WebEngineContextMenuData::MediaType)params.media_type);
ret.setHasImageContent(params.has_image_contents);
ret.setMediaFlags((WebEngineContextMenuData::MediaFlags)params.media_flags);
+ ret.setEditFlags((WebEngineContextMenuData::EditFlags)params.edit_flags);
ret.setSuggestedFileName(toQt(params.suggested_filename.data()));
ret.setIsEditable(params.is_editable);
#if BUILDFLAG(ENABLE_SPELLCHECK)
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index 2c30627ad..5bb9fa23a 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -190,8 +190,14 @@ void QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
m_contextMenuData = data;
QQuickWebEngineContextMenuRequest *request = new QQuickWebEngineContextMenuRequest(data);
+ QQmlEngine *engine = qmlEngine(q);
+
+ // TODO: this is a workaround for QTBUG-65044
+ if (!engine)
+ return;
+
// mark the object for gc by creating temporary jsvalue
- qmlEngine(q)->newQObject(request);
+ engine->newQObject(request);
Q_EMIT q->contextMenuRequested(request);
if (request->isAccepted())
@@ -203,129 +209,14 @@ void QQuickWebEngineViewPrivate::contextMenuRequested(const WebEngineContextMenu
if (!menu)
return;
- // Populate our menu
- MenuItemHandler *item = 0;
- if (data.isEditable() && !data.spellCheckerSuggestions().isEmpty()) {
- const QPointer<QQuickWebEngineView> qRef(q);
- for (int i=0; i < data.spellCheckerSuggestions().count() && i < 4; i++) {
- item = new MenuItemHandler(menu);
- QString replacement = data.spellCheckerSuggestions().at(i);
- QObject::connect(item, &MenuItemHandler::triggered, [qRef, replacement] { qRef->replaceMisspelledWord(replacement); });
- ui()->addMenuItem(item, replacement);
- }
- ui()->addMenuSeparator(menu);
- }
- if (data.linkUrl().isValid()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::OpenLinkInThisWindow); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Follow Link"));
- }
-
- if (data.selectedText().isEmpty()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::goBack);
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Back"), QStringLiteral("go-previous"), q->canGoBack());
-
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::goForward);
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Forward"), QStringLiteral("go-next"), q->canGoForward());
+ QQuickContextMenuBuilder contextMenuBuilder(data, q, menu);
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, q, &QQuickWebEngineView::reload);
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Reload"), QStringLiteral("view-refresh"));
-
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ViewSource); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("View Page Source"), QStringLiteral("view-source"), adapter->canViewSource());
- } else {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::Copy); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::Unselect); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Unselect"));
- }
-
- if (!data.linkText().isEmpty() && !data.unfilteredLinkUrl().isEmpty()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyLinkToClipboard); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Link URL"));
- }
- if (!data.linkText().isEmpty() && data.linkUrl().isValid()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadLinkToDisk); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Link"));
- }
- if (data.mediaUrl().isValid()) {
- switch (data.mediaType()) {
- case WebEngineContextMenuData::MediaTypeImage:
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageUrlToClipboard); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Image URL"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Image"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadImageToDisk); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Image"));
- break;
- case WebEngineContextMenuData::MediaTypeCanvas:
- Q_UNREACHABLE(); // mediaUrl is invalid for canvases
- break;
- case WebEngineContextMenuData::MediaTypeAudio:
- case WebEngineContextMenuData::MediaTypeVideo:
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyMediaUrlToClipboard); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Media URL"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::DownloadMediaToDisk); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Save Media"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaPlayPause); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Play/Pause"));
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaLoop); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Looping"));
- if (data.mediaFlags() & WebEngineContextMenuData::MediaHasAudio) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaMute); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Mute"));
- }
- if (data.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ToggleMediaControls); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Toggle Media Controls"));
- }
- break;
- default:
- break;
- }
- } else if (data.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Copy Image"));
- }
- if (adapter->hasInspector()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::InspectElement); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Inspect Element"));
- }
- if (isFullScreenMode()) {
- item = new MenuItemHandler(menu);
- QObject::connect(item, &MenuItemHandler::triggered, [q] { q->triggerWebAction(QQuickWebEngineView::ExitFullScreen); });
- ui()->addMenuItem(item, QQuickWebEngineView::tr("Exit Full Screen Mode"));
- }
+ // Populate our menu
+ contextMenuBuilder.initMenu();
// FIXME: expose the context menu data as an attached property to make this more useful
- if (contextMenuExtraItems) {
- ui()->addMenuSeparator(menu);
- if (QObject* menuExtras = contextMenuExtraItems->create(qmlContext(q))) {
- menuExtras->setParent(menu);
- QQmlListReference entries(menu, defaultPropertyName(menu), qmlEngine(q));
- if (entries.isValid())
- entries.append(menuExtras);
- }
- }
+ if (contextMenuExtraItems)
+ contextMenuBuilder.appendExtraItems(engine);
// Now fire the popup() method on the top level menu
ui()->showMenu(menu);
@@ -427,6 +318,11 @@ void QQuickWebEngineViewPrivate::iconChanged(const QUrl &url)
if (!faviconProvider) {
QQmlEngine *engine = qmlEngine(q);
+
+ // TODO: this is a workaround for QTBUG-65044
+ if (!engine)
+ return;
+
Q_ASSERT(engine);
faviconProvider = static_cast<QQuickWebEngineFaviconProvider *>(
engine->imageProvider(QQuickWebEngineFaviconProvider::identifier()));
@@ -1926,5 +1822,192 @@ qint64 QQuickWebEngineQuotaPermissionRequest::requestedSize() const
return d_ptr->requestedSize();
}
+QQuickContextMenuBuilder::QQuickContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data,
+ QQuickWebEngineView *view,
+ QObject *menu)
+ : QtWebEngineCore::RenderViewContextMenuQt(data)
+ , m_view(view)
+ , m_menu(menu)
+{
+}
+
+void QQuickContextMenuBuilder::appendExtraItems(QQmlEngine *engine)
+{
+ m_view->d_ptr->ui()->addMenuSeparator(m_menu);
+ if (QObject *menuExtras = m_view->d_ptr->contextMenuExtraItems->create(qmlContext(m_view))) {
+ menuExtras->setParent(m_menu);
+ QQmlListReference entries(m_menu, defaultPropertyName(m_menu), engine);
+ if (entries.isValid())
+ entries.append(menuExtras);
+ }
+}
+
+bool QQuickContextMenuBuilder::hasInspector()
+{
+ return m_view->d_ptr->adapter->hasInspector();
+}
+
+bool QQuickContextMenuBuilder::isFullScreenMode()
+{
+ return m_view->d_ptr->isFullScreenMode();
+}
+
+void QQuickContextMenuBuilder::addMenuItem(ContextMenuItem menuItem)
+{
+ MenuItemHandler *item = new MenuItemHandler(m_menu);
+ QString menuItemIcon;
+ QPointer<QQuickWebEngineView> thisRef(m_view);
+
+ switch (menuItem) {
+ case ContextMenuItem::Back:
+ QObject::connect(item, &MenuItemHandler::triggered, thisRef, &QQuickWebEngineView::goBack);
+ menuItemIcon = QStringLiteral("go-previous");
+ break;
+ case ContextMenuItem::Forward:
+ QObject::connect(item, &MenuItemHandler::triggered, thisRef, &QQuickWebEngineView::goForward);
+ menuItemIcon = QStringLiteral("go-next");
+ break;
+ case ContextMenuItem::Reload:
+ QObject::connect(item, &MenuItemHandler::triggered, thisRef, &QQuickWebEngineView::reload);
+ menuItemIcon = QStringLiteral("view-refresh");
+ break;
+ case ContextMenuItem::Cut:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::Cut); });
+ menuItemIcon = QStringLiteral("Cut");
+ break;
+ case ContextMenuItem::Copy:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::Copy); });
+ menuItemIcon = QStringLiteral("Copy");
+ break;
+
+ case ContextMenuItem::Paste:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::Paste); });
+ menuItemIcon = QStringLiteral("Paste");
+ break;
+ case ContextMenuItem::Undo:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::Undo); });
+ menuItemIcon = QStringLiteral("Undo");
+ break;
+ case ContextMenuItem::Redo:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::Redo); });
+ menuItemIcon = QStringLiteral("Redo");
+ break;
+ case ContextMenuItem::SelectAll:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::SelectAll); });
+ menuItemIcon = QStringLiteral("Select All");
+ break;
+ case ContextMenuItem::PasteAndMatchStyle:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::PasteAndMatchStyle); });
+ menuItemIcon = QStringLiteral("Paste And Match Style");
+ break;
+ case ContextMenuItem::OpenLinkInNewWindow:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::OpenLinkInNewWindow); });
+ break;
+ case ContextMenuItem::OpenLinkInNewTab:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::OpenLinkInNewTab); });
+ break;
+ case ContextMenuItem::CopyLinkToClipboard:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::CopyLinkToClipboard); });
+ break;
+ case ContextMenuItem::DownloadLinkToDisk:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::DownloadLinkToDisk); });
+ break;
+ case ContextMenuItem::CopyImageToClipboard:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::CopyImageToClipboard); });
+ break;
+ case ContextMenuItem::CopyImageUrlToClipboard:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::CopyImageUrlToClipboard); });
+ break;
+ case ContextMenuItem::DownloadImageToDisk:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::DownloadImageToDisk); });
+ break;
+ case ContextMenuItem::CopyMediaUrlToClipboard:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::CopyMediaUrlToClipboard); });
+ break;
+ case ContextMenuItem::ToggleMediaControls:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::ToggleMediaControls); });
+ break;
+ case ContextMenuItem::ToggleMediaLoop:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::ToggleMediaLoop); });
+ break;
+ case ContextMenuItem::DownloadMediaToDisk:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::DownloadMediaToDisk); });
+ break;
+ case ContextMenuItem::InspectElement:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::InspectElement); });
+ break;
+ case ContextMenuItem::ExitFullScreen:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::ExitFullScreen); });
+ break;
+ case ContextMenuItem::SavePage:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::SavePage); });
+ break;
+ case ContextMenuItem::ViewSource:
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef] { thisRef->triggerWebAction(QQuickWebEngineView::ViewSource); });
+ menuItemIcon = QStringLiteral("view-source");
+ break;
+ case ContextMenuItem::SpellingSuggestions:
+ for (int i=0; i < m_contextData.spellCheckerSuggestions().count() && i < 4; i++) {
+ item = new MenuItemHandler(m_menu);
+ QString replacement = m_contextData.spellCheckerSuggestions().at(i);
+ QObject::connect(item, &MenuItemHandler::triggered, [thisRef, replacement] { thisRef->replaceMisspelledWord(replacement); });
+ m_view->d_ptr->ui()->addMenuItem(item, replacement);
+ }
+ return;
+ case ContextMenuItem::Separator:
+ thisRef->d_ptr->ui()->addMenuSeparator(m_menu);
+ return;
+ }
+ QString menuItemName = RenderViewContextMenuQt::getMenuItemName(menuItem);
+ thisRef->d_ptr->ui()->addMenuItem(item, menuItemName, menuItemIcon, isMenuItemEnabled(menuItem));
+}
+
+bool QQuickContextMenuBuilder::isMenuItemEnabled(ContextMenuItem menuItem)
+{
+ switch (menuItem) {
+ case ContextMenuItem::Back:
+ return m_view->canGoBack();
+ case ContextMenuItem::Forward:
+ return m_view->canGoForward();
+ case ContextMenuItem::Reload:
+ return true;
+ case ContextMenuItem::Cut:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCut;
+ case ContextMenuItem::Copy:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCopy;
+ case ContextMenuItem::Paste:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste;
+ case ContextMenuItem::Undo:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanUndo;
+ case ContextMenuItem::Redo:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanRedo;
+ case ContextMenuItem::SelectAll:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanSelectAll;
+ case ContextMenuItem::PasteAndMatchStyle:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste;
+ case ContextMenuItem::OpenLinkInNewWindow:
+ case ContextMenuItem::OpenLinkInNewTab:
+ case ContextMenuItem::CopyLinkToClipboard:
+ case ContextMenuItem::DownloadLinkToDisk:
+ case ContextMenuItem::CopyImageToClipboard:
+ case ContextMenuItem::CopyImageUrlToClipboard:
+ case ContextMenuItem::DownloadImageToDisk:
+ case ContextMenuItem::CopyMediaUrlToClipboard:
+ case ContextMenuItem::ToggleMediaControls:
+ case ContextMenuItem::ToggleMediaLoop:
+ case ContextMenuItem::DownloadMediaToDisk:
+ case ContextMenuItem::InspectElement:
+ case ContextMenuItem::ExitFullScreen:
+ case ContextMenuItem::SavePage:
+ return true;
+ case ContextMenuItem::ViewSource:
+ return m_view->d_ptr->adapter->canViewSource();
+ case ContextMenuItem::SpellingSuggestions:
+ case ContextMenuItem::Separator:
+ return true;
+ }
+ Q_UNREACHABLE();
+}
+
QT_END_NAMESPACE
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 275503d14..8bda609c0 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -65,6 +65,7 @@ namespace QtWebEngineCore {
QT_BEGIN_NAMESPACE
class QQmlWebChannel;
+class QQuickContextMenuBuilder;
class QQuickWebEngineAuthenticationDialogRequest;
class QQuickWebEngineCertificateError;
class QQuickWebEngineColorDialogRequest;
@@ -583,6 +584,7 @@ private:
Q_DECLARE_PRIVATE(QQuickWebEngineView)
QScopedPointer<QQuickWebEngineViewPrivate> d_ptr;
+ friend class QQuickContextMenuBuilder;
friend class QQuickWebEngineNewViewRequest;
friend class QQuickWebEngineFaviconProvider;
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index baa89718d..cfe99a0d4 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -52,6 +52,7 @@
//
#include "qquickwebengineview_p.h"
+#include "render_view_context_menu_qt.h"
#include "web_contents_adapter_client.h"
#include <QPointer>
@@ -215,6 +216,24 @@ private:
QQuickWebEngineView *engineView() const { return static_cast<QQuickWebEngineView*>(object()); }
};
#endif // QT_NO_ACCESSIBILITY
+
+class QQuickContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt
+{
+public:
+ QQuickContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data, QQuickWebEngineView *view, QObject *menu);
+ void appendExtraItems(QQmlEngine *engine);
+
+private:
+ virtual bool hasInspector() override;
+ virtual bool isFullScreenMode() override;
+
+ virtual void addMenuItem(ContextMenuItem menuItem) override;
+ virtual bool isMenuItemEnabled(ContextMenuItem menuItem) override;
+
+ QQuickWebEngineView *m_view;
+ QObject *m_menu;
+};
+
QT_END_NAMESPACE
#endif // QQUICKWEBENGINEVIEW_P_P_H
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index a8fa98bea..ddd016329 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -1042,11 +1042,11 @@ QAction *QWebEnginePage::action(WebAction action) const
switch (action) {
case Back:
- text = tr("Back");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back);
icon = style->standardIcon(QStyle::SP_ArrowBack);
break;
case Forward:
- text = tr("Forward");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward);
icon = style->standardIcon(QStyle::SP_ArrowForward);
break;
case Stop:
@@ -1054,7 +1054,7 @@ QAction *QWebEnginePage::action(WebAction action) const
icon = style->standardIcon(QStyle::SP_BrowserStop);
break;
case Reload:
- text = tr("Reload");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload);
icon = style->standardIcon(QStyle::SP_BrowserReload);
break;
case ReloadAndBypassCache:
@@ -1062,61 +1062,61 @@ QAction *QWebEnginePage::action(WebAction action) const
icon = style->standardIcon(QStyle::SP_BrowserReload);
break;
case Cut:
- text = tr("Cut");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut);
break;
case Copy:
- text = tr("Copy");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy);
break;
case Paste:
- text = tr("Paste");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste);
break;
case Undo:
- text = tr("Undo");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo);
break;
case Redo:
- text = tr("Redo");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo);
break;
case SelectAll:
- text = tr("Select All");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll);
break;
case PasteAndMatchStyle:
- text = tr("Paste and Match Style");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle);
break;
case OpenLinkInThisWindow:
- text = tr("Open Link in This Window");
+ text = tr("Open link in this window");
break;
case OpenLinkInNewWindow:
- text = tr("Open Link in New Window");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow);
break;
case OpenLinkInNewTab:
- text = tr("Open Link in New Tab");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab);
break;
case OpenLinkInNewBackgroundTab:
- text = tr("Open Link in New Background Tab");
+ text = tr("Open link in new background tab");
break;
case CopyLinkToClipboard:
- text = tr("Copy Link URL");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard);
break;
case DownloadLinkToDisk:
- text = tr("Save Link");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk);
break;
case CopyImageToClipboard:
- text = tr("Copy Image");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard);
break;
case CopyImageUrlToClipboard:
- text = tr("Copy Image URL");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard);
break;
case DownloadImageToDisk:
- text = tr("Save Image");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk);
break;
case CopyMediaUrlToClipboard:
- text = tr("Copy Media URL");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard);
break;
case ToggleMediaControls:
- text = tr("Toggle Media Controls");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls);
break;
case ToggleMediaLoop:
- text = tr("Toggle Looping");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop);
break;
case ToggleMediaPlayPause:
text = tr("Toggle Play/Pause");
@@ -1125,13 +1125,13 @@ QAction *QWebEnginePage::action(WebAction action) const
text = tr("Toggle Mute");
break;
case DownloadMediaToDisk:
- text = tr("Save Media");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk);
break;
case InspectElement:
- text = tr("Inspect Element");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement);
break;
case ExitFullScreen:
- text = tr("Exit Full Screen Mode");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen);
break;
case RequestClose:
text = tr("Close Page");
@@ -1140,10 +1140,10 @@ QAction *QWebEnginePage::action(WebAction action) const
text = tr("Unselect");
break;
case SavePage:
- text = tr("Save &Page");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage);
break;
case ViewSource:
- text = tr("&View Page Source");
+ text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource);
break;
case ToggleBold:
text = tr("&Bold");
@@ -1656,84 +1656,11 @@ QMenu *QWebEnginePage::createStandardContextMenu()
return nullptr;
QMenu *menu = new QMenu(d->view);
- QAction *action = 0;
const WebEngineContextMenuData &contextMenuData = *d->contextData.d;
- if (contextMenuData.isEditable() && !contextMenuData.spellCheckerSuggestions().isEmpty()) {
- QPointer<QWebEnginePage> thisRef(this);
- for (int i=0; i < contextMenuData.spellCheckerSuggestions().count() && i < 4; i++) {
- QAction *action = new QAction(menu);
- QString replacement = contextMenuData.spellCheckerSuggestions().at(i);
- QObject::connect(action, &QAction::triggered, [thisRef, replacement] { if (thisRef) thisRef->replaceMisspelledWord(replacement); });
- action->setText(replacement);
- menu->addAction(action);
- }
- menu->addSeparator();
- }
-
- if (contextMenuData.linkUrl().isValid()) {
- action = QWebEnginePage::action(OpenLinkInThisWindow);
- action->setText(tr("Follow Link"));
- menu->addAction(action);
- menu->addAction(QWebEnginePage::action(DownloadLinkToDisk));
- }
- if (contextMenuData.selectedText().isEmpty()) {
- action = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), tr("&Back"), menu);
- connect(action, &QAction::triggered, d->view, &QWebEngineView::back);
- action->setEnabled(d->adapter->canGoBack());
- menu->addAction(action);
-
- action = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), tr("&Forward"), menu);
- connect(action, &QAction::triggered, d->view, &QWebEngineView::forward);
- action->setEnabled(d->adapter->canGoForward());
- menu->addAction(action);
-
- action = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), tr("&Reload"), menu);
- connect(action, &QAction::triggered, d->view, &QWebEngineView::reload);
- menu->addAction(action);
-
- menu->addAction(QWebEnginePage::action(ViewSource));
- } else {
- menu->addAction(QWebEnginePage::action(Copy));
- menu->addAction(QWebEnginePage::action(Unselect));
- }
-
- if (!contextMenuData.linkText().isEmpty() && !contextMenuData.unfilteredLinkUrl().isEmpty()) {
- menu->addAction(QWebEnginePage::action(CopyLinkToClipboard));
- }
- if (contextMenuData.mediaUrl().isValid()) {
- switch (contextMenuData.mediaType()) {
- case WebEngineContextMenuData::MediaTypeImage:
- menu->addAction(QWebEnginePage::action(DownloadImageToDisk));
- menu->addAction(QWebEnginePage::action(CopyImageUrlToClipboard));
- menu->addAction(QWebEnginePage::action(CopyImageToClipboard));
- break;
- case WebEngineContextMenuData::MediaTypeCanvas:
- Q_UNREACHABLE(); // mediaUrl is invalid for canvases
- break;
- case WebEngineContextMenuData::MediaTypeAudio:
- case WebEngineContextMenuData::MediaTypeVideo:
- menu->addAction(QWebEnginePage::action(DownloadMediaToDisk));
- menu->addAction(QWebEnginePage::action(CopyMediaUrlToClipboard));
- menu->addAction(QWebEnginePage::action(ToggleMediaPlayPause));
- menu->addAction(QWebEnginePage::action(ToggleMediaLoop));
- if (contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaHasAudio)
- menu->addAction(QWebEnginePage::action(ToggleMediaMute));
- if (contextMenuData.mediaFlags() & WebEngineContextMenuData::MediaCanToggleControls)
- menu->addAction(QWebEnginePage::action(ToggleMediaControls));
- break;
- default:
- break;
- }
- } else if (contextMenuData.mediaType() == WebEngineContextMenuData::MediaTypeCanvas) {
- menu->addAction(QWebEnginePage::action(CopyImageToClipboard));
- }
+ QContextMenuBuilder contextMenuBuilder(contextMenuData, this, menu);
- if (d->adapter->hasInspector())
- menu->addAction(QWebEnginePage::action(InspectElement));
-
- if (d->isFullScreenMode())
- menu->addAction(QWebEnginePage::action(ExitFullScreen));
+ contextMenuBuilder.initMenu();
menu->setAttribute(Qt::WA_DeleteOnClose, true);
@@ -2309,6 +2236,173 @@ const QWebEngineContextMenuData &QWebEnginePage::contextMenuData() const
return d->contextData;
}
+QContextMenuBuilder::QContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data,
+ QWebEnginePage *page,
+ QMenu *menu)
+ : QtWebEngineCore::RenderViewContextMenuQt(data)
+ , m_page(page)
+ , m_menu(menu)
+{
+}
+
+bool QContextMenuBuilder::hasInspector()
+{
+ return m_page->d_ptr->adapter->hasInspector();
+}
+
+bool QContextMenuBuilder::isFullScreenMode()
+{
+ return m_page->d_ptr->isFullScreenMode();
+}
+
+void QContextMenuBuilder::addMenuItem(ContextMenuItem menuItem)
+{
+ QPointer<QWebEnginePage> thisRef(m_page);
+ QAction *action = 0;
+
+ switch (menuItem) {
+ case ContextMenuItem::Back:
+ action = new QAction(QIcon::fromTheme(QStringLiteral("go-previous")), QWebEnginePage::tr("&Back"), m_menu);
+ QObject::connect(action, &QAction::triggered, thisRef->d_ptr->view, &QWebEngineView::back);
+ break;
+ case ContextMenuItem::Forward:
+ action = new QAction(QIcon::fromTheme(QStringLiteral("go-next")), QWebEnginePage::tr("&Forward"), m_menu);
+ QObject::connect(action, &QAction::triggered, thisRef->d_ptr->view, &QWebEngineView::forward);
+ break;
+ case ContextMenuItem::Reload:
+ action = new QAction(QIcon::fromTheme(QStringLiteral("view-refresh")), QWebEnginePage::tr("&Reload"), m_menu);
+ QObject::connect(action, &QAction::triggered, thisRef->d_ptr->view, &QWebEngineView::reload);
+ break;
+ case ContextMenuItem::Cut:
+ action = thisRef->action(QWebEnginePage::Cut);
+ break;
+ case ContextMenuItem::Copy:
+ action = thisRef->action(QWebEnginePage::Copy);
+ break;
+ case ContextMenuItem::Paste:
+ action = thisRef->action(QWebEnginePage::Paste);
+ break;
+ case ContextMenuItem::Undo:
+ action = thisRef->action(QWebEnginePage::Undo);
+ break;
+ case ContextMenuItem::Redo:
+ action = thisRef->action(QWebEnginePage::Redo);
+ break;
+ case ContextMenuItem::SelectAll:
+ action = thisRef->action(QWebEnginePage::SelectAll);
+ break;
+ case ContextMenuItem::PasteAndMatchStyle:
+ action = thisRef->action(QWebEnginePage::PasteAndMatchStyle);
+ break;
+ case ContextMenuItem::OpenLinkInNewWindow:
+ action = thisRef->action(QWebEnginePage::OpenLinkInNewWindow);
+ break;
+ case ContextMenuItem::OpenLinkInNewTab:
+ action = thisRef->action(QWebEnginePage::OpenLinkInNewTab);
+ break;
+ case ContextMenuItem::CopyLinkToClipboard:
+ action = thisRef->action(QWebEnginePage::CopyLinkToClipboard);
+ break;
+ case ContextMenuItem::DownloadLinkToDisk:
+ action = thisRef->action(QWebEnginePage::DownloadLinkToDisk);
+ break;
+ case ContextMenuItem::CopyImageToClipboard:
+ action = thisRef->action(QWebEnginePage::CopyImageToClipboard);
+ break;
+ case ContextMenuItem::CopyImageUrlToClipboard:
+ action = thisRef->action(QWebEnginePage::CopyImageUrlToClipboard);
+ break;
+ case ContextMenuItem::DownloadImageToDisk:
+ action = thisRef->action(QWebEnginePage::DownloadImageToDisk);
+ break;
+ case ContextMenuItem::CopyMediaUrlToClipboard:
+ action = thisRef->action(QWebEnginePage::CopyMediaUrlToClipboard);
+ break;
+ case ContextMenuItem::ToggleMediaControls:
+ action = thisRef->action(QWebEnginePage::ToggleMediaControls);
+ break;
+ case ContextMenuItem::ToggleMediaLoop:
+ action = thisRef->action(QWebEnginePage::ToggleMediaLoop);
+ break;
+ case ContextMenuItem::DownloadMediaToDisk:
+ action = thisRef->action(QWebEnginePage::DownloadMediaToDisk);
+ break;
+ case ContextMenuItem::InspectElement:
+ action = thisRef->action(QWebEnginePage::InspectElement);
+ break;
+ case ContextMenuItem::ExitFullScreen:
+ action = thisRef->action(QWebEnginePage::ExitFullScreen);
+ break;
+ case ContextMenuItem::SavePage:
+ action = thisRef->action(QWebEnginePage::SavePage);
+ break;
+ case ContextMenuItem::ViewSource:
+ action = thisRef->action(QWebEnginePage::ViewSource);
+ break;
+ case ContextMenuItem::SpellingSuggestions:
+ for (int i=0; i < m_contextData.spellCheckerSuggestions().count() && i < 4; i++) {
+ action = new QAction(m_menu);
+ QString replacement = m_contextData.spellCheckerSuggestions().at(i);
+ QObject::connect(action, &QAction::triggered, [thisRef, replacement] { if (thisRef) thisRef->replaceMisspelledWord(replacement); });
+ action->setText(replacement);
+ m_menu->addAction(action);
+ }
+ return;
+ case ContextMenuItem::Separator:
+ m_menu->addSeparator();
+ return;
+ }
+ action->setEnabled(isMenuItemEnabled(menuItem));
+ m_menu->addAction(action);
+}
+
+bool QContextMenuBuilder::isMenuItemEnabled(ContextMenuItem menuItem)
+{
+ switch (menuItem) {
+ case ContextMenuItem::Back:
+ return m_page->d_ptr->adapter->canGoBack();
+ case ContextMenuItem::Forward:
+ return m_page->d_ptr->adapter->canGoForward();
+ case ContextMenuItem::Reload:
+ return true;
+ case ContextMenuItem::Cut:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCut;
+ case ContextMenuItem::Copy:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanCopy;
+ case ContextMenuItem::Paste:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste;
+ case ContextMenuItem::Undo:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanUndo;
+ case ContextMenuItem::Redo:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanRedo;
+ case ContextMenuItem::SelectAll:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanSelectAll;
+ case ContextMenuItem::PasteAndMatchStyle:
+ return m_contextData.editFlags() & QtWebEngineCore::WebEngineContextMenuData::CanPaste;
+ case ContextMenuItem::OpenLinkInNewWindow:
+ case ContextMenuItem::OpenLinkInNewTab:
+ case ContextMenuItem::CopyLinkToClipboard:
+ case ContextMenuItem::DownloadLinkToDisk:
+ case ContextMenuItem::CopyImageToClipboard:
+ case ContextMenuItem::CopyImageUrlToClipboard:
+ case ContextMenuItem::DownloadImageToDisk:
+ case ContextMenuItem::CopyMediaUrlToClipboard:
+ case ContextMenuItem::ToggleMediaControls:
+ case ContextMenuItem::ToggleMediaLoop:
+ case ContextMenuItem::DownloadMediaToDisk:
+ case ContextMenuItem::InspectElement:
+ case ContextMenuItem::ExitFullScreen:
+ case ContextMenuItem::SavePage:
+ return true;
+ case ContextMenuItem::ViewSource:
+ return m_page->d_ptr->adapter->canViewSource();
+ case ContextMenuItem::SpellingSuggestions:
+ case ContextMenuItem::Separator:
+ return true;
+ }
+ Q_UNREACHABLE();
+}
+
QT_END_NAMESPACE
#include "moc_qwebenginepage.cpp"
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index 531eef6e9..7ce72258b 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -57,6 +57,7 @@ QT_BEGIN_NAMESPACE
class QMenu;
class QPrinter;
+class QContextMenuBuilder;
class QWebChannel;
class QWebEngineContextMenuData;
class QWebEngineFullScreenRequest;
@@ -374,6 +375,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_webActionTriggered(bool checked))
#endif
+ friend class QContextMenuBuilder;
friend class QWebEngineFullScreenRequest;
friend class QWebEngineView;
friend class QWebEngineViewPrivate;
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index 270849aee..301028e39 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -56,6 +56,7 @@
#include "qwebenginecallback_p.h"
#include "qwebenginecontextmenudata.h"
#include "qwebenginescriptcollection.h"
+#include "render_view_context_menu_qt.h"
#include "web_contents_adapter_client.h"
#include <QtCore/qcompilerdetection.h>
@@ -186,6 +187,22 @@ public:
#endif
};
+class QContextMenuBuilder : public QtWebEngineCore::RenderViewContextMenuQt
+{
+public:
+ QContextMenuBuilder(const QtWebEngineCore::WebEngineContextMenuData &data, QWebEnginePage *page, QMenu *menu);
+
+private:
+ virtual bool hasInspector() override;
+ virtual bool isFullScreenMode() override;
+
+ virtual void addMenuItem(ContextMenuItem entry) override;
+ virtual bool isMenuItemEnabled(ContextMenuItem entry) override;
+
+ QWebEnginePage *m_page;
+ QMenu *m_menu;
+};
+
QT_END_NAMESPACE
#endif // QWEBENGINEPAGE_P_H