From 93a91cdba2802a0b0f9fd6da063ac8bd0749e4eb Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 29 Jan 2019 15:40:45 -0800 Subject: [PATCH] webengine fileselector --- .../resources/qml/+webengine/Browser.qml | 275 ++++++++++++++++++ .../resources/qml/+webengine/InfoView.qml | 50 ++++ .../qml/+webengine/TabletBrowser.qml | 125 ++++++++ interface/resources/qml/Browser.qml | 69 +---- interface/resources/qml/InfoView.qml | 3 +- interface/resources/qml/TabletBrowser.qml | 97 +----- .../+webengine/FlickableWebViewCore.qml | 189 ++++++++++++ .../qml/controls/FlickableWebViewCore.qml | 141 +-------- .../resources/qml/controls/TabletWebView.qml | 1 - .../controlsUit/+webengine/BaseWebView.qml | 38 +++ .../resources/qml/controlsUit/BaseWebView.qml | 27 +- .../qml/controlsUit/ProxyWebView.qml | 30 ++ interface/resources/qml/controlsUit/qmldir | 1 + libraries/shared/src/shared/FileUtils.cpp | 4 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 5 +- 15 files changed, 730 insertions(+), 325 deletions(-) create mode 100644 interface/resources/qml/+webengine/Browser.qml create mode 100644 interface/resources/qml/+webengine/InfoView.qml create mode 100644 interface/resources/qml/+webengine/TabletBrowser.qml create mode 100644 interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml create mode 100644 interface/resources/qml/controlsUit/+webengine/BaseWebView.qml create mode 100644 interface/resources/qml/controlsUit/ProxyWebView.qml diff --git a/interface/resources/qml/+webengine/Browser.qml b/interface/resources/qml/+webengine/Browser.qml new file mode 100644 index 0000000000..52157bdf42 --- /dev/null +++ b/interface/resources/qml/+webengine/Browser.qml @@ -0,0 +1,275 @@ +import QtQuick 2.5 +import QtWebChannel 1.0 +import QtWebEngine 1.5 + +import controlsUit 1.0 +import stylesUit 1.0 +import "qrc:////qml//windows" + +ScrollingWindow { + id: root + HifiConstants { id: hifi } + //HifiStyles.HifiConstants { id: hifistyles } + title: "Browser" + resizable: true + destroyOnHidden: true + width: 800 + height: 600 + property variant permissionsBar: {'securityOrigin':'none','feature':'none'} + property alias url: webview.url + property alias webView: webview + + signal loadingChanged(int status) + + x: 100 + y: 100 + + Component.onCompleted: { + focus = true + shown = true + addressBar.text = webview.url + } + + function setProfile(profile) { + webview.profile = profile; + } + + function showPermissionsBar(){ + permissionsContainer.visible=true; + } + + function hidePermissionsBar(){ + permissionsContainer.visible=false; + } + + function allowPermissions(){ + webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true); + hidePermissionsBar(); + } + + function setAutoAdd(auto) { + desktop.setAutoAdd(auto); + } + + Item { + id:item + width: pane.contentWidth + implicitHeight: pane.scrollHeight + + Row { + id: buttons + spacing: 4 + anchors.top: parent.top + anchors.topMargin: 8 + anchors.left: parent.left + anchors.leftMargin: 8 + HiFiGlyphs { + id: back; + enabled: webview.canGoBack; + text: hifi.glyphs.backward + color: enabled ? hifi.colors.text : hifi.colors.disabledText + size: 48 + MouseArea { anchors.fill: parent; onClicked: webview.goBack() } + } + + HiFiGlyphs { + id: forward; + enabled: webview.canGoForward; + text: hifi.glyphs.forward + color: enabled ? hifi.colors.text : hifi.colors.disabledText + size: 48 + MouseArea { anchors.fill: parent; onClicked: webview.goForward() } + } + + HiFiGlyphs { + id: reload; + enabled: webview.canGoForward; + text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload + color: enabled ? hifi.colors.text : hifi.colors.disabledText + size: 48 + MouseArea { anchors.fill: parent; onClicked: webview.goForward() } + } + + } + + Item { + id: border + height: 48 + anchors.top: parent.top + anchors.topMargin: 8 + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.left: buttons.right + anchors.leftMargin: 8 + + Item { + id: barIcon + width: parent.height + height: parent.height + Image { + source: webview.icon; + x: (parent.height - height) / 2 + y: (parent.width - width) / 2 + sourceSize: Qt.size(width, height); + verticalAlignment: Image.AlignVCenter; + horizontalAlignment: Image.AlignHCenter + } + } + + TextField { + id: addressBar + anchors.right: parent.right + anchors.rightMargin: 8 + anchors.left: barIcon.right + anchors.leftMargin: 0 + anchors.verticalCenter: parent.verticalCenter + focus: true + colorScheme: hifi.colorSchemes.dark + placeholderText: "Enter URL" + Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") + Keys.onPressed: { + switch(event.key) { + case Qt.Key_Enter: + case Qt.Key_Return: + event.accepted = true + if (text.indexOf("http") != 0) { + text = "http://" + text; + } + root.hidePermissionsBar(); + root.keyboardRaised = false; + webview.url = text; + break; + } + } + } + } + + Rectangle { + id:permissionsContainer + visible:false + color: "#000000" + width: parent.width + anchors.top: buttons.bottom + height:40 + z:100 + gradient: Gradient { + GradientStop { position: 0.0; color: "black" } + GradientStop { position: 1.0; color: "grey" } + } + + RalewayLight { + id: permissionsInfo + anchors.right:permissionsRow.left + anchors.rightMargin: 32 + anchors.topMargin:8 + anchors.top:parent.top + text: "This site wants to use your microphone/camera" + size: 18 + color: hifi.colors.white + } + + Row { + id: permissionsRow + spacing: 4 + anchors.top:parent.top + anchors.topMargin: 8 + anchors.right: parent.right + visible: true + z:101 + + Button { + id:allow + text: "Allow" + color: hifi.buttons.blue + colorScheme: root.colorScheme + width: 120 + enabled: true + onClicked: root.allowPermissions(); + z:101 + } + + Button { + id:block + text: "Block" + color: hifi.buttons.red + colorScheme: root.colorScheme + width: 120 + enabled: true + onClicked: root.hidePermissionsBar(); + z:101 + } + } + } + + WebView { + id: webview + url: "https://highfidelity.com/" + profile: FileTypeProfile; + + // Create a global EventBridge object for raiseAndLowerKeyboard. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.Deferred + worldId: WebEngineScript.MainWorld + } + + // Detect when may want to raise and lower keyboard. + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } + + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ] + + anchors.top: buttons.bottom + anchors.topMargin: 8 + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + + onFeaturePermissionRequested: { + if (feature == 2) { // QWebEnginePage::MediaAudioCapture + grantFeaturePermission(securityOrigin, feature, true); + } else { + permissionsBar.securityOrigin = securityOrigin; + permissionsBar.feature = feature; + root.showPermissionsBar(); + } + } + + onLoadingChanged: { + if (loadRequest.status === WebEngineView.LoadSucceededStatus) { + addressBar.text = loadRequest.url + } + root.loadingChanged(loadRequest.status); + } + + onWindowCloseRequested: { + root.destroy(); + } + + Component.onCompleted: { + webChannel.registerObject("eventBridge", eventBridge); + webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); + desktop.initWebviewProfileHandlers(webview.profile); + } + } + + } // item + + + Keys.onPressed: { + switch(event.key) { + case Qt.Key_L: + if (event.modifiers == Qt.ControlModifier) { + event.accepted = true + addressBar.selectAll() + addressBar.forceActiveFocus() + } + break; + } + } +} // dialog diff --git a/interface/resources/qml/+webengine/InfoView.qml b/interface/resources/qml/+webengine/InfoView.qml new file mode 100644 index 0000000000..eb190c3c45 --- /dev/null +++ b/interface/resources/qml/+webengine/InfoView.qml @@ -0,0 +1,50 @@ +// +// InfoView.qml +// +// Created by Bradley Austin Davis on 27 Apr 2015 +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.5 +import Hifi 1.0 as Hifi + +import controlsUit 1.0 +import "qrc:////qml//windows" as Windows + +Windows.ScrollingWindow { + id: root + width: 800 + height: 800 + resizable: true + + Hifi.InfoView { + id: infoView + width: pane.contentWidth + implicitHeight: pane.scrollHeight + + WebView { + id: webview + objectName: "WebView" + anchors.fill: parent + url: infoView.url + } + } + + Component.onCompleted: { + centerWindow(root); + } + + onVisibleChanged: { + if (visible) { + centerWindow(root); + } + } + + function centerWindow() { + desktop.centerOnVisible(root); + } + +} diff --git a/interface/resources/qml/+webengine/TabletBrowser.qml b/interface/resources/qml/+webengine/TabletBrowser.qml new file mode 100644 index 0000000000..720a904231 --- /dev/null +++ b/interface/resources/qml/+webengine/TabletBrowser.qml @@ -0,0 +1,125 @@ +import QtQuick 2.5 +import QtWebChannel 1.0 +import QtWebEngine 1.5 + +import "controls" +import controlsUit 1.0 as HifiControls +import "styles" as HifiStyles +import stylesUit 1.0 +import "windows" + +Item { + id: root + HifiConstants { id: hifi } + HifiStyles.HifiConstants { id: hifistyles } + + height: 600 + property variant permissionsBar: {'securityOrigin':'none','feature':'none'} + property alias url: webview.url + + property bool canGoBack: webview.canGoBack + property bool canGoForward: webview.canGoForward + + + signal loadingChanged(int status) + + x: 0 + y: 0 + + function setProfile(profile) { + webview.profile = profile; + } + + WebEngineView { + id: webview + objectName: "webEngineView" + x: 0 + y: 0 + width: parent.width + height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height + + profile: HFWebEngineProfile; + + property string userScriptUrl: "" + + // creates a global EventBridge object. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.DocumentCreation + worldId: WebEngineScript.MainWorld + } + + // detects when to raise and lower virtual keyboard + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } + + // User script. + WebEngineScript { + id: userScript + sourceUrl: webview.userScriptUrl + injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } + + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + + property string newUrl: "" + + Component.onCompleted: { + webChannel.registerObject("eventBridge", eventBridge); + webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); + + // Ensure the JS from the web-engine makes it to our logging + webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); + }); + + webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; + web.address = url; + } + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + onLoadingChanged: { + keyboardRaised = false; + punctuationMode = false; + keyboard.resetShiftMode(false); + + // Required to support clicking on "hifi://" links + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + urlAppend(loadRequest.url.toString()) + var url = loadRequest.url.toString(); + if (urlHandler.canHandleUrl(url)) { + if (urlHandler.handleUrl(url)) { + root.stop(); + } + } + } + } + + onNewViewRequested: { + request.openIn(webView); + } + + HifiControls.WebSpinner { } + } + + Keys.onPressed: { + switch(event.key) { + case Qt.Key_L: + if (event.modifiers == Qt.ControlModifier) { + event.accepted = true + addressBar.selectAll() + addressBar.forceActiveFocus() + } + break; + } + } +} diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 4ddee15a10..78ffb51e67 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,16 +1,14 @@ import QtQuick 2.5 -import QtWebChannel 1.0 -import QtWebEngine 1.5 import controlsUit 1.0 -import "styles" as HifiStyles import stylesUit 1.0 + import "windows" ScrollingWindow { id: root HifiConstants { id: hifi } - HifiStyles.HifiConstants { id: hifistyles } + //HifiStyles.HifiConstants { id: hifistyles } title: "Browser" resizable: true destroyOnHidden: true @@ -32,7 +30,6 @@ ScrollingWindow { } function setProfile(profile) { - webview.profile = profile; } function showPermissionsBar(){ @@ -44,7 +41,6 @@ ScrollingWindow { } function allowPermissions(){ - webview.grantFeaturePermission(permissionsBar.securityOrigin, permissionsBar.feature, true); hidePermissionsBar(); } @@ -68,7 +64,7 @@ ScrollingWindow { id: back; enabled: webview.canGoBack; text: hifi.glyphs.backward - color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText + color: enabled ? hifi.colors.text : hifi.colors.disabledText size: 48 MouseArea { anchors.fill: parent; onClicked: webview.goBack() } } @@ -77,7 +73,7 @@ ScrollingWindow { id: forward; enabled: webview.canGoForward; text: hifi.glyphs.forward - color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText + color: enabled ? hifi.colors.text : hifi.colors.disabledText size: 48 MouseArea { anchors.fill: parent; onClicked: webview.goForward() } } @@ -86,7 +82,7 @@ ScrollingWindow { id: reload; enabled: webview.canGoForward; text: webview.loading ? hifi.glyphs.close : hifi.glyphs.reload - color: enabled ? hifistyles.colors.text : hifistyles.colors.disabledText + color: enabled ? hifi.colors.text : hifi.colors.disabledText size: 48 MouseArea { anchors.fill: parent; onClicked: webview.goForward() } } @@ -202,61 +198,10 @@ ScrollingWindow { } } - WebView { + ProxyWebView { id: webview + anchors.centerIn: parent url: "https://highfidelity.com/" - profile: FileTypeProfile; - - // Create a global EventBridge object for raiseAndLowerKeyboard. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.Deferred - worldId: WebEngineScript.MainWorld - } - - // Detect when may want to raise and lower keyboard. - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard ] - - anchors.top: buttons.bottom - anchors.topMargin: 8 - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - - onFeaturePermissionRequested: { - if (feature == 2) { // QWebEnginePage::MediaAudioCapture - grantFeaturePermission(securityOrigin, feature, true); - } else { - permissionsBar.securityOrigin = securityOrigin; - permissionsBar.feature = feature; - root.showPermissionsBar(); - } - } - - onLoadingChanged: { - if (loadRequest.status === WebEngineView.LoadSucceededStatus) { - addressBar.text = loadRequest.url - } - root.loadingChanged(loadRequest.status); - } - - onWindowCloseRequested: { - root.destroy(); - } - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - desktop.initWebviewProfileHandlers(webview.profile); - } } } // item diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 8c5900b4c3..5c2c7fcff9 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -19,13 +19,12 @@ Windows.ScrollingWindow { width: 800 height: 800 resizable: true - Hifi.InfoView { id: infoView width: pane.contentWidth implicitHeight: pane.scrollHeight - WebView { + ProxyWebView { id: webview objectName: "WebView" anchors.fill: parent diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 720a904231..f83a9c81a5 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -1,17 +1,11 @@ import QtQuick 2.5 -import QtWebChannel 1.0 -import QtWebEngine 1.5 -import "controls" import controlsUit 1.0 as HifiControls -import "styles" as HifiStyles import stylesUit 1.0 -import "windows" Item { id: root HifiConstants { id: hifi } - HifiStyles.HifiConstants { id: hifistyles } height: 600 property variant permissionsBar: {'securityOrigin':'none','feature':'none'} @@ -30,96 +24,9 @@ Item { webview.profile = profile; } - WebEngineView { + HifiControls.ProxyWebView { id: webview - objectName: "webEngineView" - x: 0 - y: 0 width: parent.width - height: keyboardEnabled && keyboardRaised ? parent.height - keyboard.height : parent.height - - profile: HFWebEngineProfile; - - property string userScriptUrl: "" - - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: webview.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - property string newUrl: "" - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - - // Ensure the JS from the web-engine makes it to our logging - webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); - }); - - webview.profile.httpUserAgent = "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36"; - web.address = url; - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - - onLoadingChanged: { - keyboardRaised = false; - punctuationMode = false; - keyboard.resetShiftMode(false); - - // Required to support clicking on "hifi://" links - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - urlAppend(loadRequest.url.toString()) - var url = loadRequest.url.toString(); - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - root.stop(); - } - } - } - } - - onNewViewRequested: { - request.openIn(webView); - } - - HifiControls.WebSpinner { } - } - - Keys.onPressed: { - switch(event.key) { - case Qt.Key_L: - if (event.modifiers == Qt.ControlModifier) { - event.accepted = true - addressBar.selectAll() - addressBar.forceActiveFocus() - } - break; - } + height: parent.height } } diff --git a/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml new file mode 100644 index 0000000000..823d0107a2 --- /dev/null +++ b/interface/resources/qml/controls/+webengine/FlickableWebViewCore.qml @@ -0,0 +1,189 @@ +import QtQuick 2.7 +import QtWebEngine 1.5 +import QtWebChannel 1.0 + +import QtQuick.Controls 2.2 + +import stylesUit 1.0 as StylesUIt + +Item { + id: flick + + property alias url: webViewCore.url + property alias canGoBack: webViewCore.canGoBack + property alias webViewCore: webViewCore + property alias webViewCoreProfile: webViewCore.profile + property string webViewCoreUserAgent + + property string userScriptUrl: "" + property string urlTag: "noDownload=false"; + + signal newViewRequestedCallback(var request) + signal loadingChangedCallback(var loadRequest) + + + width: parent.width + + property bool interactive: false + + property bool blurOnCtrlShift: true + + StylesUIt.HifiConstants { + id: hifi + } + + function stop() { + webViewCore.stop(); + } + + Timer { + id: delayedUnfocuser + repeat: false + interval: 200 + onTriggered: { + + // The idea behind this is to delay unfocusing, so that fast lower/raise will not result actual unfocusing. + // Fast lower/raise happens every time keyboard is being re-raised (see the code below in OffscreenQmlSurface::setKeyboardRaised) + // + // if (raised) { + // item->setProperty("keyboardRaised", QVariant(!raised)); + // } + // + // item->setProperty("keyboardRaised", QVariant(raised)); + // + + webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) { + console.log('unfocus completed: ', result); + }); + } + } + + function unfocus() { + delayedUnfocuser.start(); + } + + function stopUnfocus() { + delayedUnfocuser.stop(); + } + + function onLoadingChanged(loadRequest) { + if (WebEngineView.LoadStartedStatus === loadRequest.status) { + + // Required to support clicking on "hifi://" links + var url = loadRequest.url.toString(); + url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag; + if (urlHandler.canHandleUrl(url)) { + if (urlHandler.handleUrl(url)) { + webViewCore.stop(); + } + } + } + + if (WebEngineView.LoadFailedStatus === loadRequest.status) { + console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString()); + } + + if (WebEngineView.LoadSucceededStatus === loadRequest.status) { + //disable Chromium's scroll bars + } + } + + WebEngineView { + id: webViewCore + + width: parent.width + height: parent.height + + profile: HFWebEngineProfile; + settings.pluginsEnabled: true + settings.touchIconsEnabled: true + settings.allowRunningInsecureContent: true + + // creates a global EventBridge object. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.DocumentCreation + worldId: WebEngineScript.MainWorld + } + + // detects when to raise and lower virtual keyboard + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } + + // User script. + WebEngineScript { + id: userScript + sourceUrl: flick.userScriptUrl + injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } + + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + + Component.onCompleted: { + webChannel.registerObject("eventBridge", eventBridge); + webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); + + if (webViewCoreUserAgent !== undefined) { + webViewCore.profile.httpUserAgent = webViewCoreUserAgent + } else { + webViewCore.profile.httpUserAgent += " (HighFidelityInterface)"; + } + // Ensure the JS from the web-engine makes it to our logging + webViewCore.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); + }); + } + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + //disable popup + onContextMenuRequested: { + request.accepted = true; + } + + onNewViewRequested: { + newViewRequestedCallback(request) + } + + // Prior to 5.10, the WebEngineView loading property is true during initial page loading and then stays false + // as in-page javascript adds more html content. However, in 5.10 there is a bug such that adding html turns + // loading true, and never turns it false again. safeLoading provides a workaround, but it should be removed + // when QT fixes this. + property bool safeLoading: false + property bool loadingLatched: false + property var loadingRequest: null + onLoadingChanged: { + webViewCore.loadingRequest = loadRequest; + webViewCore.safeLoading = webViewCore.loading && !loadingLatched; + webViewCore.loadingLatched |= webViewCore.loading; + } + onSafeLoadingChanged: { + flick.onLoadingChanged(webViewCore.loadingRequest) + loadingChangedCallback(webViewCore.loadingRequest) + } + } + + AnimatedImage { + //anchoring doesnt works here when changing content size + x: flick.width/2 - width/2 + y: flick.height/2 - height/2 + source: "../../icons/loader-snake-64-w.gif" + visible: webViewCore.safeLoading && /^(http.*|)$/i.test(webViewCore.url.toString()) + playing: visible + z: 10000 + } + + Keys.onPressed: { + if (blurOnCtrlShift && (event.modifiers & Qt.ShiftModifier) && (event.modifiers & Qt.ControlModifier)) { + webViewCore.focus = false; + } + } +} diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index 823d0107a2..a844c8b624 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -1,10 +1,9 @@ import QtQuick 2.7 -import QtWebEngine 1.5 -import QtWebChannel 1.0 import QtQuick.Controls 2.2 import stylesUit 1.0 as StylesUIt +import controlsUit 1.0 as ControlsUit Item { id: flick @@ -33,157 +32,21 @@ Item { } function stop() { - webViewCore.stop(); - } - Timer { - id: delayedUnfocuser - repeat: false - interval: 200 - onTriggered: { - - // The idea behind this is to delay unfocusing, so that fast lower/raise will not result actual unfocusing. - // Fast lower/raise happens every time keyboard is being re-raised (see the code below in OffscreenQmlSurface::setKeyboardRaised) - // - // if (raised) { - // item->setProperty("keyboardRaised", QVariant(!raised)); - // } - // - // item->setProperty("keyboardRaised", QVariant(raised)); - // - - webViewCore.runJavaScript("if (document.activeElement) document.activeElement.blur();", function(result) { - console.log('unfocus completed: ', result); - }); - } } function unfocus() { - delayedUnfocuser.start(); } function stopUnfocus() { - delayedUnfocuser.stop(); } function onLoadingChanged(loadRequest) { - if (WebEngineView.LoadStartedStatus === loadRequest.status) { - - // Required to support clicking on "hifi://" links - var url = loadRequest.url.toString(); - url = (url.indexOf("?") >= 0) ? url + urlTag : url + "?" + urlTag; - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - webViewCore.stop(); - } - } - } - - if (WebEngineView.LoadFailedStatus === loadRequest.status) { - console.log("Tablet WebEngineView failed to load url: " + loadRequest.url.toString()); - } - - if (WebEngineView.LoadSucceededStatus === loadRequest.status) { - //disable Chromium's scroll bars - } } - WebEngineView { + ControlsUit.ProxyWebView { id: webViewCore - width: parent.width height: parent.height - - profile: HFWebEngineProfile; - settings.pluginsEnabled: true - settings.touchIconsEnabled: true - settings.allowRunningInsecureContent: true - - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: flick.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - - if (webViewCoreUserAgent !== undefined) { - webViewCore.profile.httpUserAgent = webViewCoreUserAgent - } else { - webViewCore.profile.httpUserAgent += " (HighFidelityInterface)"; - } - // Ensure the JS from the web-engine makes it to our logging - webViewCore.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Entity JS message: " + sourceID + " " + lineNumber + " " + message); - }); - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - - //disable popup - onContextMenuRequested: { - request.accepted = true; - } - - onNewViewRequested: { - newViewRequestedCallback(request) - } - - // Prior to 5.10, the WebEngineView loading property is true during initial page loading and then stays false - // as in-page javascript adds more html content. However, in 5.10 there is a bug such that adding html turns - // loading true, and never turns it false again. safeLoading provides a workaround, but it should be removed - // when QT fixes this. - property bool safeLoading: false - property bool loadingLatched: false - property var loadingRequest: null - onLoadingChanged: { - webViewCore.loadingRequest = loadRequest; - webViewCore.safeLoading = webViewCore.loading && !loadingLatched; - webViewCore.loadingLatched |= webViewCore.loading; - } - onSafeLoadingChanged: { - flick.onLoadingChanged(webViewCore.loadingRequest) - loadingChangedCallback(webViewCore.loadingRequest) - } - } - - AnimatedImage { - //anchoring doesnt works here when changing content size - x: flick.width/2 - width/2 - y: flick.height/2 - height/2 - source: "../../icons/loader-snake-64-w.gif" - visible: webViewCore.safeLoading && /^(http.*|)$/i.test(webViewCore.url.toString()) - playing: visible - z: 10000 - } - - Keys.onPressed: { - if (blurOnCtrlShift && (event.modifiers & Qt.ShiftModifier) && (event.modifiers & Qt.ControlModifier)) { - webViewCore.focus = false; - } } } diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 3959dbf01b..9cbbd48a22 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -1,5 +1,4 @@ import QtQuick 2.7 -import QtWebEngine 1.5 import controlsUit 1.0 as HiFiControls import "../styles" as HifiStyles import stylesUit 1.0 diff --git a/interface/resources/qml/controlsUit/+webengine/BaseWebView.qml b/interface/resources/qml/controlsUit/+webengine/BaseWebView.qml new file mode 100644 index 0000000000..fdd9c12220 --- /dev/null +++ b/interface/resources/qml/controlsUit/+webengine/BaseWebView.qml @@ -0,0 +1,38 @@ +// +// WebView.qml +// +// Created by Bradley Austin Davis on 12 Jan 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +import QtQuick 2.7 +import QtWebEngine 1.5 + +WebEngineView { + id: root + + Component.onCompleted: { + console.log("Connecting JS messaging to Hifi Logging") + // Ensure the JS from the web-engine makes it to our logging + root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { + console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); + }); + } + + onLoadingChanged: { + // Required to support clicking on "hifi://" links + if (WebEngineView.LoadStartedStatus == loadRequest.status) { + var url = loadRequest.url.toString(); + if (urlHandler.canHandleUrl(url)) { + if (urlHandler.handleUrl(url)) { + root.stop(); + } + } + } + } + + WebSpinner { } +} diff --git a/interface/resources/qml/controlsUit/BaseWebView.qml b/interface/resources/qml/controlsUit/BaseWebView.qml index fdd9c12220..52b2d1f3db 100644 --- a/interface/resources/qml/controlsUit/BaseWebView.qml +++ b/interface/resources/qml/controlsUit/BaseWebView.qml @@ -8,31 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.7 -import QtWebEngine 1.5 +import "." -WebEngineView { +ProxyWebView { id: root - - Component.onCompleted: { - console.log("Connecting JS messaging to Hifi Logging") - // Ensure the JS from the web-engine makes it to our logging - root.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) { - console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message); - }); - } - - onLoadingChanged: { - // Required to support clicking on "hifi://" links - if (WebEngineView.LoadStartedStatus == loadRequest.status) { - var url = loadRequest.url.toString(); - if (urlHandler.canHandleUrl(url)) { - if (urlHandler.handleUrl(url)) { - root.stop(); - } - } - } - } - - WebSpinner { } } diff --git a/interface/resources/qml/controlsUit/ProxyWebView.qml b/interface/resources/qml/controlsUit/ProxyWebView.qml new file mode 100644 index 0000000000..adcc472831 --- /dev/null +++ b/interface/resources/qml/controlsUit/ProxyWebView.qml @@ -0,0 +1,30 @@ +import QtQuick 2.7 +import stylesUit 1.0 + +Rectangle { + HifiConstants { + id: hifi + } + + color: hifi.colors.darkGray + + signal onNewViewRequested(); + + property string url: ""; + property bool canGoBack: false + property bool canGoForward: false + property string icon: "" + property var profile: {} + + property bool safeLoading: false + property bool loadingLatched: false + property var loadingRequest: null + + + Text { + anchors.centerIn: parent + text: "This feature is not supported" + font.pixelSize: 32 + color: hifi.colors.white + } +} diff --git a/interface/resources/qml/controlsUit/qmldir b/interface/resources/qml/controlsUit/qmldir index d0577f5575..e1665df40e 100644 --- a/interface/resources/qml/controlsUit/qmldir +++ b/interface/resources/qml/controlsUit/qmldir @@ -29,6 +29,7 @@ TextEdit 1.0 TextEdit.qml TextField 1.0 TextField.qml ToolTip 1.0 ToolTip.qml Tree 1.0 Tree.qml +ProxyWebView 1.0 ProxyWebView.qml VerticalSpacer 1.0 VerticalSpacer.qml WebGlyphButton 1.0 WebGlyphButton.qml WebSpinner 1.0 WebSpinner.qml diff --git a/libraries/shared/src/shared/FileUtils.cpp b/libraries/shared/src/shared/FileUtils.cpp index 0709a53602..f65acccfa1 100644 --- a/libraries/shared/src/shared/FileUtils.cpp +++ b/libraries/shared/src/shared/FileUtils.cpp @@ -33,6 +33,10 @@ const QStringList& FileUtils::getFileSelectors() { #if defined(USE_GLES) extraSelectors << "gles"; #endif + +#ifndef Q_OS_ANDROID + extraSelectors << "webengine"; +#endif }); return extraSelectors; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index f67a356078..71bb65509f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -49,6 +49,7 @@ #include #include "SecurityImageProvider.h" +#include "shared/FileUtils.h" #include "types/FileTypeProfile.h" #include "types/HFWebEngineProfile.h" #include "types/SoundEffect.h" @@ -237,7 +238,9 @@ void OffscreenQmlSurface::clearFocusItem() { void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { Parent::initializeEngine(engine); - new QQmlFileSelector(engine); + QQmlFileSelector* fileSelector = new QQmlFileSelector(engine); + fileSelector->setExtraSelectors(FileUtils::getFileSelectors()); + static std::once_flag once; std::call_once(once, [] { qRegisterMetaType();