summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/webengine/quicknanobrowser/BrowserWindow.qml2
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc16
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.cpp26
-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/core/web_engine_settings.cpp2
-rw-r--r--src/core/web_engine_settings.h1
-rw-r--r--src/webengine/api/qquickwebenginecontextmenurequest.cpp116
-rw-r--r--src/webengine/api/qquickwebenginecontextmenurequest_p.h38
-rw-r--r--src/webengine/api/qquickwebenginesettings.cpp25
-rw-r--r--src/webengine/api/qquickwebenginesettings_p.h4
-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/webengine/doc/src/webengineview_lgpl.qdoc4
-rw-r--r--src/webengine/plugin/plugin.cpp2
-rw-r--r--src/webengine/plugin/plugins.qmltypes66
-rw-r--r--src/webenginewidgets/api/qwebenginecontextmenudata.cpp87
-rw-r--r--src/webenginewidgets/api/qwebenginecontextmenudata.h36
-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
-rw-r--r--src/webenginewidgets/api/qwebenginesettings.cpp2
-rw-r--r--src/webenginewidgets/api/qwebenginesettings.h1
-rw-r--r--src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc5
-rw-r--r--tests/auto/quick/qmltests/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp66
-rw-r--r--tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp77
-rw-r--r--tests/auto/widgets/widgets.pro2
32 files changed, 1375 insertions, 251 deletions
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index f3bd8e457..be1e42c73 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -487,7 +487,7 @@ ApplicationWindow {
id: devToolsView
visible: devToolsEnabled.checked
height: 400
- inspectedView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
+ inspectedView: visible && tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
index 4f44d9f6c..4b39463b6 100644
--- a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -184,16 +184,18 @@
\section2 Adding Context Menu Items
- We add menu items to the context menu, so that users can right-click a link
- to have it opened in the same tab, a new window, or a new tab. We override
- QWebEngineView::contextMenuEvent and use
+ We add a menu item to the context menu, so that users can right-click to have an inspector
+ opened in a new window. We override QWebEngineView::contextMenuEvent and use
QWebEnginePage::createStandardContextMenu to create a default QMenu with a
default list of QWebEnginePage::WebAction actions.
- The default name for QWebEnginePage::OpenLinkInThisWindow action is
- \uicontrol Follow. For clarity, we rename it
- \uicontrol {Open Link in This Tab}. Also, we add the actions for opening
- links in a separate window or in a new tab:
+ The default name for QWebEnginePage::InspectElement action is
+ \uicontrol Inspect. For clarity, we rename it to \uicontrol {Open Inspector In New Window} when
+ there is no Inspector present yet,
+ and \uicontrol {Inspect Element} when it's already created.
+
+ We also check if the QWebEnginePage::ViewSource action is in the menu, because if it's not
+ we have to add a separator as well.
\quotefromfile webenginewidgets/simplebrowser/webview.cpp
\skipto WebView::contextMenuEvent(
diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp
index ab42c4a0a..fcbb543f2 100644
--- a/examples/webenginewidgets/simplebrowser/webview.cpp
+++ b/examples/webenginewidgets/simplebrowser/webview.cpp
@@ -177,21 +177,21 @@ QWebEngineView *WebView::createWindow(QWebEnginePage::WebWindowType type)
void WebView::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *menu = page()->createStandardContextMenu();
- const QList<QAction*> actions = menu->actions();
- auto it = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::OpenLinkInThisWindow));
- if (it != actions.cend()) {
- (*it)->setText(tr("Open Link in This Tab"));
- ++it;
- QAction *before(it == actions.cend() ? nullptr : *it);
- menu->insertAction(before, page()->action(QWebEnginePage::OpenLinkInNewWindow));
- menu->insertAction(before, page()->action(QWebEnginePage::OpenLinkInNewTab));
- }
- it = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::InspectElement));
- if (it == actions.cend()) {
+ const QList<QAction *> actions = menu->actions();
+ auto inspectElement = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::InspectElement));
+ if (inspectElement == actions.cend()) {
+ auto viewSource = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::ViewSource));
+ if (viewSource == actions.cend())
+ menu->addSeparator();
+
QAction *action = new QAction(menu);
- action->setText("Inspect Element");
+ action->setText("Open inspector in new window");
connect(action, &QAction::triggered, [this]() { emit devToolsRequested(page()); });
- menu->addAction(action);
+
+ QAction *before(inspectElement == actions.cend() ? nullptr : *inspectElement);
+ menu->insertAction(before, action);
+ } else {
+ (*inspectElement)->setText(tr("Inspect element"));
}
menu->popup(event->globalPos());
}
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/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp
index 2a789ef91..d16c2bd15 100644
--- a/src/core/web_engine_settings.cpp
+++ b/src/core/web_engine_settings.cpp
@@ -297,6 +297,7 @@ void WebEngineSettings::initDefaults()
playbackRequiresUserGesture = (commandLine->GetSwitchValueASCII(switches::kAutoplayPolicy) != switches::autoplay::kNoUserGestureRequiredPolicy);
s_defaultAttributes.insert(PlaybackRequiresUserGesture, playbackRequiresUserGesture);
s_defaultAttributes.insert(WebRTCPublicInterfacesOnly, false);
+ s_defaultAttributes.insert(JavascriptCanPaste, false);
}
if (s_defaultFontFamilies.isEmpty()) {
@@ -388,6 +389,7 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p
? content::AutoplayPolicy::kUserGestureRequired
: content::AutoplayPolicy::kNoUserGestureRequired;
}
+ prefs->dom_paste_enabled = testAttribute(JavascriptCanPaste);
// Fonts settings.
prefs->standard_font_family_map[content::kCommonScript] = toString16(fontFamily(StandardFont));
diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h
index 06e6ac59c..eba9bf7ea 100644
--- a/src/core/web_engine_settings.h
+++ b/src/core/web_engine_settings.h
@@ -90,6 +90,7 @@ public:
ShowScrollBars,
PlaybackRequiresUserGesture,
WebRTCPublicInterfacesOnly,
+ JavascriptCanPaste,
};
// Must match the values from the public API in qwebenginesettings.h.
diff --git a/src/webengine/api/qquickwebenginecontextmenurequest.cpp b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
index c53e28d93..dea89b9ab 100644
--- a/src/webengine/api/qquickwebenginecontextmenurequest.cpp
+++ b/src/webengine/api/qquickwebenginecontextmenurequest.cpp
@@ -42,6 +42,7 @@
QT_BEGIN_NAMESPACE
+// Match MediaType enum
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeNone,
QQuickWebEngineContextMenuRequest::MediaTypeNone)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeImage,
@@ -57,6 +58,52 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeFile,
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypePlugin,
QQuickWebEngineContextMenuRequest::MediaTypePlugin)
+// Match MediaFlag enum
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaNone,
+ QQuickWebEngineContextMenuRequest::MediaNone)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaInError,
+ QQuickWebEngineContextMenuRequest::MediaInError)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaPaused,
+ QQuickWebEngineContextMenuRequest::MediaPaused)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaMuted,
+ QQuickWebEngineContextMenuRequest::MediaMuted)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaLoop,
+ QQuickWebEngineContextMenuRequest::MediaLoop)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanSave,
+ QQuickWebEngineContextMenuRequest::MediaCanSave)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaHasAudio,
+ QQuickWebEngineContextMenuRequest::MediaHasAudio)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanToggleControls,
+ QQuickWebEngineContextMenuRequest::MediaCanToggleControls)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaControls,
+ QQuickWebEngineContextMenuRequest::MediaControls)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanPrint,
+ QQuickWebEngineContextMenuRequest::MediaCanPrint)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanRotate,
+ QQuickWebEngineContextMenuRequest::MediaCanRotate)
+
+// Match EditFlag enum
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanDoNone,
+ QQuickWebEngineContextMenuRequest::CanDoNone)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanUndo,
+ QQuickWebEngineContextMenuRequest::CanUndo)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanRedo,
+ QQuickWebEngineContextMenuRequest::CanRedo)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanCut,
+ QQuickWebEngineContextMenuRequest::CanCut)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanCopy,
+ QQuickWebEngineContextMenuRequest::CanCopy)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanPaste,
+ QQuickWebEngineContextMenuRequest::CanPaste)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanDelete,
+ QQuickWebEngineContextMenuRequest::CanDelete)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanSelectAll,
+ QQuickWebEngineContextMenuRequest::CanSelectAll)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanTranslate,
+ QQuickWebEngineContextMenuRequest::CanTranslate)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanEditRichly,
+ QQuickWebEngineContextMenuRequest::CanEditRichly)
+
/*!
\qmltype ContextMenuRequest
\instantiates QQuickWebEngineContextMenuRequest
@@ -272,4 +319,73 @@ void QQuickWebEngineContextMenuRequest::setAccepted(bool accepted)
m_accepted = accepted;
}
+/*!
+ \qmlproperty flags ContextMenuRequest::mediaFlags
+ \readonly
+ \since QtWebEngine 1.7
+
+ The current media element's status and its available operations.
+ \c MediaNone if the selected web page content is not a media element.
+
+ \value ContextMenuRequest.MediaNone
+ Not a media element.
+ \value ContextMenuRequest.MediaInError
+ An error occurred.
+ \value ContextMenuRequest.MediaPaused
+ Media is paused.
+ \value ContextMenuRequest.MediaMuted
+ Media is muted.
+ \value ContextMenuRequest.MediaLoop
+ Media can be looped.
+ \value ContextMenuRequest.MediaCanSave
+ Media can be saved.
+ \value ContextMenuRequest.MediaHasAudio
+ Media has audio.
+ \value ContextMenuRequest.MediaCanToggleControls
+ Media can show controls.
+ \value ContextMenuRequest.MediaControls
+ Media controls are shown.
+ \value ContextMenuRequest.MediaCanPrint
+ Media is printable.
+ \value ContextMenuRequest.MediaCanRotate
+ Media is rotatable.
+*/
+QQuickWebEngineContextMenuRequest::MediaFlags QQuickWebEngineContextMenuRequest::mediaFlags() const
+{
+ return static_cast<QQuickWebEngineContextMenuRequest::MediaFlags>(m_data->mediaFlags());
+}
+
+/*!
+ \qmlproperty flags ContextMenuRequest::editFlags
+ \readonly
+ \since QtWebEngine 1.7
+
+ The available edit operations in the current context or \c CanDoNone if no actions are available.
+
+ \value ContextMenuRequest.CanDoNone
+ Nothing can be done.
+ \value ContextMenuRequest.CanUndo
+ Undo is available.
+ \value ContextMenuRequest.CanRedo
+ Redo is available.
+ \value ContextMenuRequest.CanCut
+ Cut is available.
+ \value ContextMenuRequest.CanCopy
+ Copy is available.
+ \value ContextMenuRequest.CanPaste
+ Paste is available.
+ \value ContextMenuRequest.CanDelete
+ Delete is available.
+ \value ContextMenuRequest.CanSelectAll
+ Select All is available.
+ \value ContextMenuRequest.CanTranslate
+ Translate is available.
+ \value ContextMenuRequest.CanEditRichly
+ Context is richly editable.
+*/
+QQuickWebEngineContextMenuRequest::EditFlags QQuickWebEngineContextMenuRequest::editFlags() const
+{
+ return static_cast<QQuickWebEngineContextMenuRequest::EditFlags>(m_data->editFlags());
+}
+
QT_END_NAMESPACE
diff --git a/src/webengine/api/qquickwebenginecontextmenurequest_p.h b/src/webengine/api/qquickwebenginecontextmenurequest_p.h
index 3d2de14a2..5f0b0c282 100644
--- a/src/webengine/api/qquickwebenginecontextmenurequest_p.h
+++ b/src/webengine/api/qquickwebenginecontextmenurequest_p.h
@@ -75,6 +75,38 @@ public:
};
Q_ENUM(MediaType)
+ // Must match QWebEngineCore::WebEngineContextMenuData::MediaFlags:
+ enum MediaFlag {
+ MediaNone = 0x0,
+ MediaInError = 0x1,
+ MediaPaused = 0x2,
+ MediaMuted = 0x4,
+ MediaLoop = 0x8,
+ MediaCanSave = 0x10,
+ MediaHasAudio = 0x20,
+ MediaCanToggleControls = 0x40,
+ MediaControls = 0x80,
+ MediaCanPrint = 0x100,
+ MediaCanRotate = 0x200,
+ };
+ Q_DECLARE_FLAGS(MediaFlags, MediaFlag)
+
+
+ // Must match QWebEngineCore::WebEngineContextMenuData::EditFlags:
+ enum EditFlag {
+ CanDoNone = 0x0,
+ CanUndo = 0x1,
+ CanRedo = 0x2,
+ CanCut = 0x4,
+ CanCopy = 0x8,
+ CanPaste = 0x10,
+ CanDelete = 0x20,
+ CanSelectAll = 0x40,
+ CanTranslate = 0x80,
+ CanEditRichly = 0x100,
+ };
+ Q_DECLARE_FLAGS(EditFlags, EditFlag)
+
Q_PROPERTY(int x READ x CONSTANT FINAL)
Q_PROPERTY(int y READ y CONSTANT FINAL)
Q_PROPERTY(QString selectedText READ selectedText CONSTANT FINAL)
@@ -86,6 +118,8 @@ public:
Q_PROPERTY(QString misspelledWord READ misspelledWord CONSTANT FINAL)
Q_PROPERTY(QStringList spellCheckerSuggestions READ spellCheckerSuggestions CONSTANT FINAL)
Q_PROPERTY(bool accepted READ isAccepted WRITE setAccepted FINAL)
+ Q_PROPERTY(MediaFlags mediaFlags READ mediaFlags CONSTANT FINAL REVISION 1)
+ Q_PROPERTY(EditFlags editFlags READ editFlags CONSTANT FINAL REVISION 1)
~QQuickWebEngineContextMenuRequest();
int x() const;
@@ -100,11 +134,15 @@ public:
QStringList spellCheckerSuggestions() const;
bool isAccepted() const;
void setAccepted(bool accepted);
+ MediaFlags mediaFlags() const;
+ EditFlags editFlags() const;
private:
QQuickWebEngineContextMenuRequest(const QtWebEngineCore::WebEngineContextMenuData &data, QObject *parent = nullptr);
QScopedPointer<QtWebEngineCore::WebEngineContextMenuData> m_data;
bool m_accepted;
+ Q_FLAGS(MediaFlags)
+ Q_FLAGS(EditFlags)
friend class QQuickWebEngineView;
friend class QQuickWebEngineViewPrivate;
Q_DISABLE_COPY(QQuickWebEngineContextMenuRequest)
diff --git a/src/webengine/api/qquickwebenginesettings.cpp b/src/webengine/api/qquickwebenginesettings.cpp
index 71b0deeca..6203f20f1 100644
--- a/src/webengine/api/qquickwebenginesettings.cpp
+++ b/src/webengine/api/qquickwebenginesettings.cpp
@@ -130,6 +130,9 @@ bool QQuickWebEngineSettings::javascriptCanOpenWindows() const
Allows JavaScript programs to read from or write to the clipboard.
Writing to the clipboard is always allowed if it is specifically requested by the user.
+ To enable also the pasting of clipboard content from JavaScript,
+ use javascriptCanPaste.
+
Disabled by default.
*/
bool QQuickWebEngineSettings::javascriptCanAccessClipboard() const
@@ -426,6 +429,20 @@ bool QQuickWebEngineSettings::webRTCPublicInterfacesOnly() const
}
/*!
+ \qmlproperty bool WebEngineSettings::javascriptCanPaste
+ \since QtWebEngine 1.7
+
+ Enables JavaScript \c{execCommand("paste")}.
+ This also requires enabling javascriptCanAccessClipboard.
+
+ Disabled by default.
+*/
+bool QQuickWebEngineSettings::javascriptCanPaste() const
+{
+ return d_ptr->testAttribute(WebEngineSettings::JavascriptCanPaste);
+}
+
+/*!
\qmlproperty string WebEngineSettings::defaultTextEncoding
\since QtWebEngine 1.2
@@ -667,6 +684,14 @@ void QQuickWebEngineSettings::setPlaybackRequiresUserGesture(bool on)
Q_EMIT playbackRequiresUserGestureChanged();
}
+void QQuickWebEngineSettings::setJavascriptCanPaste(bool on)
+{
+ bool wasOn = d_ptr->testAttribute(WebEngineSettings::JavascriptCanPaste);
+ d_ptr->setAttribute(WebEngineSettings::JavascriptCanPaste, on);
+ if (wasOn != on)
+ Q_EMIT javascriptCanPasteChanged();
+}
+
void QQuickWebEngineSettings::setUnknownUrlSchemePolicy(QQuickWebEngineSettings::UnknownUrlSchemePolicy policy)
{
WebEngineSettings::UnknownUrlSchemePolicy oldPolicy = d_ptr->unknownUrlSchemePolicy();
diff --git a/src/webengine/api/qquickwebenginesettings_p.h b/src/webengine/api/qquickwebenginesettings_p.h
index 60baa7323..2911ee283 100644
--- a/src/webengine/api/qquickwebenginesettings_p.h
+++ b/src/webengine/api/qquickwebenginesettings_p.h
@@ -91,6 +91,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject {
Q_PROPERTY(UnknownUrlSchemePolicy unknownUrlSchemePolicy READ unknownUrlSchemePolicy WRITE setUnknownUrlSchemePolicy NOTIFY unknownUrlSchemePolicyChanged REVISION 6 FINAL)
Q_PROPERTY(bool playbackRequiresUserGesture READ playbackRequiresUserGesture WRITE setPlaybackRequiresUserGesture NOTIFY playbackRequiresUserGestureChanged REVISION 6 FINAL)
Q_PROPERTY(bool webRTCPublicInterfacesOnly READ webRTCPublicInterfacesOnly WRITE setWebRTCPublicInterfacesOnly NOTIFY webRTCPublicInterfacesOnlyChanged REVISION 6 FINAL)
+ Q_PROPERTY(bool javascriptCanPaste READ javascriptCanPaste WRITE setJavascriptCanPaste NOTIFY javascriptCanPaste REVISION 6 FINAL)
public:
enum UnknownUrlSchemePolicy {
@@ -131,6 +132,7 @@ public:
UnknownUrlSchemePolicy unknownUrlSchemePolicy() const;
bool playbackRequiresUserGesture() const;
bool webRTCPublicInterfacesOnly() const;
+ bool javascriptCanPaste() const;
void setAutoLoadImages(bool on);
void setJavascriptEnabled(bool on);
@@ -160,6 +162,7 @@ public:
void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy);
void setPlaybackRequiresUserGesture(bool on);
void setWebRTCPublicInterfacesOnly(bool on);
+ void setJavascriptCanPaste(bool on);
signals:
void autoLoadImagesChanged();
@@ -190,6 +193,7 @@ signals:
Q_REVISION(6) void unknownUrlSchemePolicyChanged();
Q_REVISION(6) void playbackRequiresUserGestureChanged();
Q_REVISION(6) void webRTCPublicInterfacesOnlyChanged();
+ Q_REVISION(6) void javascriptCanPasteChanged();
private:
explicit QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings = 0);
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index f49b2c6bb..19e85315b 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()));
@@ -1932,5 +1828,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/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index fadce39ad..c6985b082 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -1386,6 +1386,10 @@
will navigate to an internal URL with the developer tools of
the view set.
+ It is recommended to unset this property when developer tools
+ are not visible; otherwise some debug information may appear
+ in the inspected WebEngineView.
+
\sa devToolView
*/
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index 03ce5a332..5f9d16158 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -125,6 +125,8 @@ public:
qmlRegisterUncreatableType<QQuickWebEngineContextMenuRequest>(uri, 1, 4, "ContextMenuRequest",
msgUncreatableType("ContextMenuRequest"));
+ qmlRegisterUncreatableType<QQuickWebEngineContextMenuRequest, 1>(uri, 1, 7, "ContextMenuRequest",
+ msgUncreatableType("ContextMenuRequest"));
qmlRegisterUncreatableType<QQuickWebEngineAuthenticationDialogRequest>(uri, 1, 4, "AuthenticationDialogRequest",
msgUncreatableType("AuthenticationDialogRequest"));
qmlRegisterUncreatableType<QQuickWebEngineJavaScriptDialogRequest>(uri, 1, 4, "JavaScriptDialogRequest",
diff --git a/src/webengine/plugin/plugins.qmltypes b/src/webengine/plugin/plugins.qmltypes
index b57aa4498..43d7d9064 100644
--- a/src/webengine/plugin/plugins.qmltypes
+++ b/src/webengine/plugin/plugins.qmltypes
@@ -84,9 +84,12 @@ Module {
Component {
name: "QQuickWebEngineContextMenuRequest"
prototype: "QObject"
- exports: ["QtWebEngine/ContextMenuRequest 1.4"]
+ exports: [
+ "QtWebEngine/ContextMenuRequest 1.4",
+ "QtWebEngine/ContextMenuRequest 1.7"
+ ]
isCreatable: false
- exportMetaObjectRevisions: [0]
+ exportMetaObjectRevisions: [0, 1]
Enum {
name: "MediaType"
values: {
@@ -99,6 +102,37 @@ Module {
"MediaTypePlugin": 6
}
}
+ Enum {
+ name: "MediaFlags"
+ values: {
+ "MediaNone": 0,
+ "MediaInError": 1,
+ "MediaPaused": 2,
+ "MediaMuted": 4,
+ "MediaLoop": 8,
+ "MediaCanSave": 16,
+ "MediaHasAudio": 32,
+ "MediaCanToggleControls": 64,
+ "MediaControls": 128,
+ "MediaCanPrint": 256,
+ "MediaCanRotate": 512
+ }
+ }
+ Enum {
+ name: "EditFlags"
+ values: {
+ "CanDoNone": 0,
+ "CanUndo": 1,
+ "CanRedo": 2,
+ "CanCut": 4,
+ "CanCopy": 8,
+ "CanPaste": 16,
+ "CanDelete": 32,
+ "CanSelectAll": 64,
+ "CanTranslate": 128,
+ "CanEditRichly": 256
+ }
+ }
Property { name: "x"; type: "int"; isReadonly: true }
Property { name: "y"; type: "int"; isReadonly: true }
Property { name: "selectedText"; type: "string"; isReadonly: true }
@@ -110,6 +144,8 @@ Module {
Property { name: "misspelledWord"; type: "string"; isReadonly: true }
Property { name: "spellCheckerSuggestions"; type: "QStringList"; isReadonly: true }
Property { name: "accepted"; type: "bool" }
+ Property { name: "mediaFlags"; revision: 1; type: "MediaFlags"; isReadonly: true }
+ Property { name: "editFlags"; revision: 1; type: "EditFlags"; isReadonly: true }
}
Component {
name: "QQuickWebEngineDownloadItem"
@@ -198,6 +234,7 @@ Module {
Property { name: "interruptReasonString"; revision: 4; type: "string"; isReadonly: true }
Property { name: "isFinished"; revision: 5; type: "bool"; isReadonly: true }
Property { name: "isPaused"; revision: 5; type: "bool"; isReadonly: true }
+ Property { name: "isSavePageDownload"; revision: 6; type: "bool"; isReadonly: true }
Signal { name: "savePageFormatChanged"; revision: 2 }
Signal { name: "mimeTypeChanged"; revision: 1 }
Signal { name: "typeChanged"; revision: 3 }
@@ -527,10 +564,11 @@ Module {
"QtWebEngine/WebEngineSettings 1.3",
"QtWebEngine/WebEngineSettings 1.4",
"QtWebEngine/WebEngineSettings 1.5",
- "QtWebEngine/WebEngineSettings 1.6"
+ "QtWebEngine/WebEngineSettings 1.6",
+ "QtWebEngine/WebEngineSettings 1.7"
]
isCreatable: false
- exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5]
+ exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6]
Enum {
name: "UnknownUrlSchemePolicy"
values: {
@@ -565,6 +603,8 @@ Module {
Property { name: "allowWindowActivationFromJavaScript"; revision: 5; type: "bool" }
Property { name: "showScrollBars"; revision: 5; type: "bool" }
Property { name: "unknownUrlSchemePolicy"; revision: 6; type: "UnknownUrlSchemePolicy" }
+ Property { name: "playbackRequiresUserGesture"; revision: 6; type: "bool" }
+ Property { name: "webRTCPublicInterfacesOnly"; revision: 6; type: "bool" }
Signal { name: "fullScreenSupportEnabledChanged"; revision: 1 }
Signal { name: "screenCaptureEnabledChanged"; revision: 2 }
Signal { name: "webGLEnabledChanged"; revision: 2 }
@@ -578,6 +618,8 @@ Module {
Signal { name: "allowWindowActivationFromJavaScriptChanged"; revision: 5 }
Signal { name: "showScrollBarsChanged"; revision: 5 }
Signal { name: "unknownUrlSchemePolicyChanged"; revision: 6 }
+ Signal { name: "playbackRequiresUserGestureChanged"; revision: 6 }
+ Signal { name: "webRTCPublicInterfacesOnlyChanged"; revision: 6 }
}
Component {
name: "QQuickWebEngineSingleton"
@@ -606,9 +648,10 @@ Module {
"QtWebEngine/WebEngineView 1.3",
"QtWebEngine/WebEngineView 1.4",
"QtWebEngine/WebEngineView 1.5",
- "QtWebEngine/WebEngineView 1.6"
+ "QtWebEngine/WebEngineView 1.6",
+ "QtWebEngine/WebEngineView 1.7"
]
- exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6]
+ exportMetaObjectRevisions: [0, 1, 2, 3, 4, 5, 6, 7]
Enum {
name: "NavigationRequestAction"
values: {
@@ -921,6 +964,9 @@ Module {
Property { name: "audioMuted"; revision: 3; type: "bool" }
Property { name: "recentlyAudible"; revision: 3; type: "bool"; isReadonly: true }
Property { name: "webChannelWorld"; revision: 3; type: "uint" }
+ Property { name: "inspectedView"; revision: 7; type: "QQuickWebEngineView"; isPointer: true }
+ Property { name: "devToolsView"; revision: 7; type: "QQuickWebEngineView"; isPointer: true }
+ Property { name: "testSupport"; type: "QQuickWebEngineTestSupport"; isPointer: true }
Signal {
name: "loadingChanged"
Parameter { name: "loadRequest"; type: "QQuickWebEngineLoadRequest"; isPointer: true }
@@ -1056,6 +1102,14 @@ Module {
revision: 7
Parameter { name: "request"; type: "QQuickWebEngineQuotaPermissionRequest" }
}
+ Signal {
+ name: "geometryChangeRequested"
+ revision: 7
+ Parameter { name: "geometry"; type: "QRect" }
+ Parameter { name: "frameGeometry"; type: "QRect" }
+ }
+ Signal { name: "inspectedViewChanged"; revision: 7 }
+ Signal { name: "devToolsViewChanged"; revision: 7 }
Method {
name: "runJavaScript"
Parameter { type: "string" }
diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
index 63e11175b..82c17fe3b 100644
--- a/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
+++ b/src/webenginewidgets/api/qwebenginecontextmenudata.cpp
@@ -43,6 +43,7 @@
QT_BEGIN_NAMESPACE
+// Match MediaType enum
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeNone, QWebEngineContextMenuData::MediaTypeNone)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeImage, QWebEngineContextMenuData::MediaTypeImage)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeAudio, QWebEngineContextMenuData::MediaTypeAudio)
@@ -51,6 +52,31 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeCanvas, Q
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypeFile, QWebEngineContextMenuData::MediaTypeFile)
ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypePlugin, QWebEngineContextMenuData::MediaTypePlugin)
+// Match MediaFlag enum
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaNone, QWebEngineContextMenuData::MediaNone)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaInError, QWebEngineContextMenuData::MediaInError)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaPaused, QWebEngineContextMenuData::MediaPaused)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaMuted, QWebEngineContextMenuData::MediaMuted)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaLoop, QWebEngineContextMenuData::MediaLoop)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanSave, QWebEngineContextMenuData::MediaCanSave)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaHasAudio, QWebEngineContextMenuData::MediaHasAudio)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanToggleControls, QWebEngineContextMenuData::MediaCanToggleControls)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaControls, QWebEngineContextMenuData::MediaControls)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanPrint, QWebEngineContextMenuData::MediaCanPrint)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaCanRotate, QWebEngineContextMenuData::MediaCanRotate)
+
+// Match EditFlag enum
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanDoNone, QWebEngineContextMenuData::CanDoNone)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanUndo, QWebEngineContextMenuData::CanUndo)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanRedo, QWebEngineContextMenuData::CanRedo)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanCut, QWebEngineContextMenuData::CanCut)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanCopy, QWebEngineContextMenuData::CanCopy)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanPaste, QWebEngineContextMenuData::CanPaste)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanDelete, QWebEngineContextMenuData::CanDelete)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanSelectAll, QWebEngineContextMenuData::CanSelectAll)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanTranslate, QWebEngineContextMenuData::CanTranslate)
+ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::CanEditRichly, QWebEngineContextMenuData::CanEditRichly)
+
/*!
\class QWebEngineContextMenuData
\since 5.7
@@ -78,6 +104,46 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebEngineContextMenuData::MediaTypePlugin, Q
*/
/*!
+ \enum QWebEngineContextMenuData::EditFlag
+ \readonly
+ \since 5.11
+
+ The available edit operations in the current context.
+
+ \value CanDoNone Nothing can be done.
+ \value CanUndo Undo is available.
+ \value CanRedo Redo is available.
+ \value CanCut Cut is available.
+ \value CanCopy Copy is available.
+ \value CanPaste Paste is available.
+ \value CanDelete Delete is available.
+ \value CanSelectAll Select All is available.
+ \value CanTranslate Translate is available.
+ \value CanEditRichly Context is richly editable.
+*/
+
+/*!
+ \enum QWebEngineContextMenuData::MediaFlag
+ \readonly
+ \since 5.11
+
+ The current media element's status and its available operations.
+ \c MediaNone if the selected web page content is not a media element.
+
+ \value MediaNone Not a media element.
+ \value MediaInError An error occurred.
+ \value MediaPaused Media is paused.
+ \value MediaMuted Media is muted.
+ \value MediaLoop Media can be looped.
+ \value MediaCanSave Media can be saved.
+ \value MediaHasAudio Media has audio.
+ \value MediaCanToggleControls Media can show controls.
+ \value MediaControls Media controls are shown.
+ \value MediaCanPrint Media is printable.
+ \value MediaCanRotate Media is rotatable.
+*/
+
+/*!
Constructs null context menu data.
*/
QWebEngineContextMenuData::QWebEngineContextMenuData() : d(nullptr)
@@ -224,4 +290,25 @@ QWebEngineContextMenuData &QWebEngineContextMenuData::operator=(const QWebEngine
return *this;
}
+/*!
+ Returns the current media element's status and its available operations.
+ \c MediaNone if the selected web page content is not a media element.
+*/
+QWebEngineContextMenuData::MediaFlags QWebEngineContextMenuData::mediaFlags() const
+{
+ if (d)
+ return static_cast<QWebEngineContextMenuData::MediaFlags>(d->mediaFlags());
+ return QWebEngineContextMenuData::MediaNone;
+}
+
+/*!
+ Returns the available edit operations in the current context or \c CanDoNone if no actions are available.
+*/
+QWebEngineContextMenuData::EditFlags QWebEngineContextMenuData::editFlags() const
+{
+ if (d)
+ return static_cast<QWebEngineContextMenuData::EditFlags>(d->editFlags());
+ return QWebEngineContextMenuData::CanDoNone;
+}
+
QT_END_NAMESPACE
diff --git a/src/webenginewidgets/api/qwebenginecontextmenudata.h b/src/webenginewidgets/api/qwebenginecontextmenudata.h
index 97cfe9f65..8c2e9c5e5 100644
--- a/src/webenginewidgets/api/qwebenginecontextmenudata.h
+++ b/src/webenginewidgets/api/qwebenginecontextmenudata.h
@@ -67,6 +67,38 @@ public:
MediaTypeFile,
MediaTypePlugin
};
+
+ // Must match QWebEngineCore::WebEngineContextMenuData::MediaFlags:
+ enum MediaFlag {
+ MediaNone = 0x0,
+ MediaInError = 0x1,
+ MediaPaused = 0x2,
+ MediaMuted = 0x4,
+ MediaLoop = 0x8,
+ MediaCanSave = 0x10,
+ MediaHasAudio = 0x20,
+ MediaCanToggleControls = 0x40,
+ MediaControls = 0x80,
+ MediaCanPrint = 0x100,
+ MediaCanRotate = 0x200,
+ };
+ Q_DECLARE_FLAGS(MediaFlags, MediaFlag)
+
+ // Must match QWebEngineCore::WebEngineContextMenuData::EditFlags:
+ enum EditFlag {
+ CanDoNone = 0x0,
+ CanUndo = 0x1,
+ CanRedo = 0x2,
+ CanCut = 0x4,
+ CanCopy = 0x8,
+ CanPaste = 0x10,
+ CanDelete = 0x20,
+ CanSelectAll = 0x40,
+ CanTranslate = 0x80,
+ CanEditRichly = 0x100,
+ };
+ Q_DECLARE_FLAGS(EditFlags, EditFlag)
+
bool isValid() const;
QPoint position() const;
@@ -78,12 +110,16 @@ public:
bool isContentEditable() const;
QString misspelledWord() const;
QStringList spellCheckerSuggestions() const;
+ MediaFlags mediaFlags() const;
+ EditFlags editFlags() const;
private:
void reset();
typedef QtWebEngineCore::WebEngineContextMenuData QWebEngineContextDataPrivate;
QWebEngineContextMenuData &operator=(const QWebEngineContextDataPrivate &priv);
const QWebEngineContextDataPrivate *d;
+ Q_FLAGS(MediaFlags)
+ Q_FLAGS(EditFlags)
friend class QWebEnginePagePrivate;
friend class QWebEnginePage;
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
diff --git a/src/webenginewidgets/api/qwebenginesettings.cpp b/src/webenginewidgets/api/qwebenginesettings.cpp
index b829c5799..32f9b75cd 100644
--- a/src/webenginewidgets/api/qwebenginesettings.cpp
+++ b/src/webenginewidgets/api/qwebenginesettings.cpp
@@ -105,6 +105,8 @@ static WebEngineSettings::Attribute toWebEngineAttribute(QWebEngineSettings::Web
return WebEngineSettings::PlaybackRequiresUserGesture;
case QWebEngineSettings::WebRTCPublicInterfacesOnly:
return WebEngineSettings::WebRTCPublicInterfacesOnly;
+ case QWebEngineSettings::JavascriptCanPaste:
+ return WebEngineSettings::JavascriptCanPaste;
default:
return WebEngineSettings::UnsupportedInCoreSettings;
diff --git a/src/webenginewidgets/api/qwebenginesettings.h b/src/webenginewidgets/api/qwebenginesettings.h
index 81b6c2937..1815396b6 100644
--- a/src/webenginewidgets/api/qwebenginesettings.h
+++ b/src/webenginewidgets/api/qwebenginesettings.h
@@ -94,6 +94,7 @@ public:
ShowScrollBars,
PlaybackRequiresUserGesture,
WebRTCPublicInterfacesOnly,
+ JavascriptCanPaste,
};
enum FontSize {
diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
index cde26f66b..a8ee59bf4 100644
--- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
@@ -94,6 +94,8 @@
\value JavascriptCanAccessClipboard
Allows JavaScript programs to read from and write to the clipboard.
Writing to the clipboard is always allowed if it is specifically requested by the user.
+ See JavascriptCanPaste to also allow pasting the content of the clipboard content from
+ JavaScript.
Disabled by default.
\value LinksIncludedInFocusChain
Includes hyperlinks in the keyboard focus chain. Enabled by default.
@@ -173,6 +175,9 @@
Inhibits playback of media content until the user interacts with
the page. This is similar to how Chrome on Android behaves, while
the default behavior when it is disabled is similar to Chrome on desktops.
+ \value JavascriptCanPaste
+ Enables JavaScript \c{execCommand("paste")}. This also requires
+ enabling JavascriptCanAccessClipboard.
Disabled by default. (Added in Qt 5.11)
\value WebRTCPublicInterfacesOnly
Limits WebRTC to public IP addresses only. When disabled WebRTC may also use
diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST
index 54a3185d6..b511f1a35 100644
--- a/tests/auto/quick/qmltests/BLACKLIST
+++ b/tests/auto/quick/qmltests/BLACKLIST
@@ -16,3 +16,6 @@ osx
[WebViewFindText::test_findTextInterruptedByLoad]
*
+
+[WebEngineViewSource::test_viewSourceURL]
+*
diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
index a64197b1c..f8f742ae1 100644
--- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
+++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
@@ -31,6 +31,8 @@
#include <QScopedPointer>
#include <QtCore/qelapsedtimer.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qguiapplication.h>
#include <QtGui/qpa/qwindowsysteminterface.h>
#include <QtQml/QQmlEngine>
#include <QtTest/QtTest>
@@ -84,6 +86,8 @@ private Q_SLOTS:
void changeLocale();
void userScripts();
+ void javascriptClipboard_data();
+ void javascriptClipboard();
private:
inline QQuickWebEngineView *newWebEngineView();
@@ -860,5 +864,67 @@ void tst_QQuickWebEngineView::userScripts()
list.clear();
}
+void tst_QQuickWebEngineView::javascriptClipboard_data()
+{
+ QTest::addColumn<bool>("javascriptCanAccessClipboard");
+ QTest::addColumn<bool>("javascriptCanPaste");
+ QTest::addColumn<bool>("copyResult");
+ QTest::addColumn<bool>("pasteResult");
+
+ QTest::newRow("default") << false << false << false << false;
+ QTest::newRow("canCopy") << true << false << true << false;
+ // paste command requires both permissions
+ QTest::newRow("canPaste") << false << true << false << false;
+ QTest::newRow("canCopyAndPaste") << true << true << true << true;
+}
+
+void tst_QQuickWebEngineView::javascriptClipboard()
+{
+ QFETCH(bool, javascriptCanAccessClipboard);
+ QFETCH(bool, javascriptCanPaste);
+ QFETCH(bool, copyResult);
+ QFETCH(bool, pasteResult);
+
+ // check defaults
+ QCOMPARE(webEngineView()->settings()->javascriptCanAccessClipboard(), false);
+ QCOMPARE(webEngineView()->settings()->javascriptCanPaste(), false);
+
+ // check accessors
+ webEngineView()->settings()->setJavascriptCanAccessClipboard(javascriptCanAccessClipboard);
+ webEngineView()->settings()->setJavascriptCanPaste(javascriptCanPaste);
+ QCOMPARE(webEngineView()->settings()->javascriptCanAccessClipboard(),
+ javascriptCanAccessClipboard);
+ QCOMPARE(webEngineView()->settings()->javascriptCanPaste(), javascriptCanPaste);
+
+ QQuickWebEngineView *view = webEngineView();
+ view->loadHtml("<html><body>"
+ "<input type='text' value='OriginalText' id='myInput'/>"
+ "</body></html>");
+ QVERIFY(waitForLoadSucceeded(view));
+
+ // make sure that 'OriginalText' is selected
+ evaluateJavaScriptSync(view, "document.getElementById('myInput').select()");
+ QCOMPARE(evaluateJavaScriptSync(view, "window.getSelection().toString()").toString(),
+ "OriginalText");
+
+ // Check that the actual settings work by the
+ // - return value of queryCommandEnabled and
+ // - return value of execCommand
+ // - comparing the clipboard / input field
+ QGuiApplication::clipboard()->clear();
+ QCOMPARE(evaluateJavaScriptSync(view, "document.queryCommandEnabled('copy')").toBool(),
+ copyResult);
+ QCOMPARE(evaluateJavaScriptSync(view, "document.execCommand('copy')").toBool(), copyResult);
+ QCOMPARE(QGuiApplication::clipboard()->text(),
+ (copyResult ? QString("OriginalText") : QString()));
+
+ QGuiApplication::clipboard()->setText("AnotherText");
+ QCOMPARE(evaluateJavaScriptSync(view, "document.queryCommandEnabled('paste')").toBool(),
+ pasteResult);
+ QCOMPARE(evaluateJavaScriptSync(view, "document.execCommand('paste')").toBool(), pasteResult);
+ QCOMPARE(evaluateJavaScriptSync(view, "document.getElementById('myInput').value").toString(),
+ (pasteResult ? QString("AnotherText") : QString("OriginalText")));
+}
+
QTEST_MAIN(tst_QQuickWebEngineView)
#include "tst_qquickwebengineview.moc"
diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
index 5cbcf4ec0..9c008cb90 100644
--- a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
+++ b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp
@@ -17,11 +17,17 @@
Boston, MA 02110-1301, USA.
*/
+#include "../util.h"
+
#include <QtTest/QtTest>
+#include <qwebenginepage.h>
#include <qwebengineprofile.h>
#include <qwebenginesettings.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qguiapplication.h>
+
class tst_QWebEngineSettings: public QObject {
Q_OBJECT
@@ -29,6 +35,8 @@ private Q_SLOTS:
void resetAttributes();
void defaultFontFamily_data();
void defaultFontFamily();
+ void javascriptClipboard_data();
+ void javascriptClipboard();
};
void tst_QWebEngineSettings::resetAttributes()
@@ -85,6 +93,75 @@ void tst_QWebEngineSettings::defaultFontFamily()
QVERIFY(!settings->fontFamily(static_cast<QWebEngineSettings::FontFamily>(fontFamily)).isEmpty());
}
+void tst_QWebEngineSettings::javascriptClipboard_data()
+{
+ QTest::addColumn<bool>("javascriptCanAccessClipboard");
+ QTest::addColumn<bool>("javascriptCanPaste");
+ QTest::addColumn<bool>("copyResult");
+ QTest::addColumn<bool>("pasteResult");
+
+ QTest::newRow("default") << false << false << false << false;
+ QTest::newRow("canCopy") << true << false << true << false;
+ // paste command requires both permissions
+ QTest::newRow("canPaste") << false << true << false << false;
+ QTest::newRow("canCopyAndPaste") << true << true << true << true;
+}
+
+void tst_QWebEngineSettings::javascriptClipboard()
+{
+ QFETCH(bool, javascriptCanAccessClipboard);
+ QFETCH(bool, javascriptCanPaste);
+ QFETCH(bool, copyResult);
+ QFETCH(bool, pasteResult);
+
+ QWebEnginePage page;
+
+ // check defaults
+ QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard),
+ false);
+ QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste), false);
+
+ // check accessors
+ page.settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard,
+ javascriptCanAccessClipboard);
+ page.settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste,
+ javascriptCanPaste);
+ QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard),
+ javascriptCanAccessClipboard);
+ QCOMPARE(page.settings()->testAttribute(QWebEngineSettings::JavascriptCanPaste),
+ javascriptCanPaste);
+
+ QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
+ page.setHtml("<html><body>"
+ "<input type='text' value='OriginalText' id='myInput'/>"
+ "</body></html>");
+ QVERIFY(loadFinishedSpy.wait());
+
+ // make sure that 'OriginalText' is selected
+ evaluateJavaScriptSync(&page, "document.getElementById('myInput').select()");
+ QCOMPARE(evaluateJavaScriptSync(&page, "window.getSelection().toString()").toString(),
+ "OriginalText");
+
+ // Check that the actual settings work by the
+ // - return value of queryCommandEnabled and
+ // - return value of execCommand
+ // - comparing the clipboard / input field
+ QGuiApplication::clipboard()->clear();
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('copy')").toBool(),
+ copyResult);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('copy')").toBool(), copyResult);
+ QCOMPARE(QApplication::clipboard()->text(),
+ (copyResult ? QString("OriginalText") : QString()));
+
+
+ QGuiApplication::clipboard()->setText("AnotherText");
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('paste')").toBool(),
+ pasteResult);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('paste')").toBool(), pasteResult);
+ QCOMPARE(evaluateJavaScriptSync(&page, "document.getElementById('myInput').value").toString(),
+ (pasteResult ? QString("AnotherText") : QString("OriginalText")));
+}
+
QTEST_MAIN(tst_QWebEngineSettings)
#include "tst_qwebenginesettings.moc"
diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro
index ba1b254f4..36dfaba9f 100644
--- a/tests/auto/widgets/widgets.pro
+++ b/tests/auto/widgets/widgets.pro
@@ -32,5 +32,5 @@ qtConfig(webengine-spellchecker):!cross_compile {
boot2qt: SUBDIRS -= qwebengineaccessibility qwebenginedefaultsurfaceformat \
qwebenginefaviconmanager qwebenginepage qwebenginehistory \
qwebengineprofile qwebengineschemes qwebenginescript \
- qwebengineview qwebenginedownloads
+ qwebengineview qwebenginedownloads qwebenginesettings