diff options
author | Balazs Egedi <egedib@inf.u-szeged.hu> | 2021-08-17 12:59:28 +0200 |
---|---|---|
committer | Balazs Egedi <egedib@inf.u-szeged.hu> | 2021-09-13 10:25:48 +0200 |
commit | a32ef7057c01fbcadcf451e7f2b785f7b3dd3942 (patch) | |
tree | 15258c16f6369ad9f3318101102d7da1b3002927 /examples/webenginequick/quicknanobrowser | |
parent | 498c4ac362cb6cbee8a30c8cc46fa4253bf93ee0 (diff) |
Rename Quick examples' folder from webengine to webenginequick
Fix webengine directory path in project files and comments
Pick-to: 6.2 6.2.0
Change-Id: I06ed9ee41111e7135fa9feb152ad2a5eb2262b76
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'examples/webenginequick/quicknanobrowser')
19 files changed, 1853 insertions, 0 deletions
diff --git a/examples/webenginequick/quicknanobrowser/ApplicationRoot.qml b/examples/webenginequick/quicknanobrowser/ApplicationRoot.qml new file mode 100644 index 000000000..cd40a7fdb --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/ApplicationRoot.qml @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtWebEngine + +QtObject { + id: root + + property QtObject defaultProfile: WebEngineProfile { + storageName: "Profile" + offTheRecord: false + } + + property QtObject otrProfile: WebEngineProfile { + offTheRecord: true + } + + property Component browserWindowComponent: BrowserWindow { + applicationRoot: root + } + property Component browserDialogComponent: BrowserDialog { + onClosing: destroy() + } + function createWindow(profile) { + var newWindow = browserWindowComponent.createObject(root); + newWindow.currentWebView.profile = profile; + profile.downloadRequested.connect(newWindow.onDownloadRequested); + return newWindow; + } + function createDialog(profile) { + var newDialog = browserDialogComponent.createObject(root); + newDialog.currentWebView.profile = profile; + return newDialog; + } + function load(url) { + var browserWindow = createWindow(defaultProfile); + browserWindow.currentWebView.url = url; + } +} diff --git a/examples/webenginequick/quicknanobrowser/BrowserDialog.qml b/examples/webenginequick/quicknanobrowser/BrowserDialog.qml new file mode 100644 index 000000000..281f44904 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/BrowserDialog.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Window +import QtWebEngine + +Window { + id: window + property alias currentWebView: webView + flags: Qt.Dialog | Qt.WindowStaysOnTopHint + width: 800 + height: 600 + visible: true + onClosing: destroy() + WebEngineView { + id: webView + anchors.fill: parent + + onGeometryChangeRequested: function(geometry) { + window.x = geometry.x + window.y = geometry.y + window.width = geometry.width + window.height = geometry.height + } + } +} diff --git a/examples/webenginequick/quicknanobrowser/BrowserWindow.qml b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml new file mode 100644 index 000000000..0da1bc043 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/BrowserWindow.qml @@ -0,0 +1,801 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Qt.labs.settings +import QtQml +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Window +import QtWebEngine + +ApplicationWindow { + id: browserWindow + property QtObject applicationRoot + property Item currentWebView: tabBar.currentIndex < tabBar.count ? tabLayout.children[tabBar.currentIndex] : null + property int previousVisibility: Window.Windowed + property int createdTabs: 0 + + width: 1300 + height: 900 + visible: true + title: currentWebView && currentWebView.title + + // Make sure the Qt.WindowFullscreenButtonHint is set on OS X. + Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint + + onCurrentWebViewChanged: { + findBar.reset(); + } + + // When using style "mac", ToolButtons are not supposed to accept focus. + property bool platformIsMac: Qt.platform.os == "osx" + + Settings { + id : appSettings + property alias autoLoadImages: loadImages.checked + property alias javaScriptEnabled: javaScriptEnabled.checked + property alias errorPageEnabled: errorPageEnabled.checked + property alias pluginsEnabled: pluginsEnabled.checked + property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked + property alias autoLoadIconsForPage: autoLoadIconsForPage.checked + property alias touchIconsEnabled: touchIconsEnabled.checked + property alias webRTCPublicInterfacesOnly : webRTCPublicInterfacesOnly.checked + property alias devToolsEnabled: devToolsEnabled.checked + property alias pdfViewerEnabled: pdfViewerEnabled.checked + } + + Action { + shortcut: "Ctrl+D" + onTriggered: { + downloadView.visible = !downloadView.visible; + } + } + Action { + id: focus + shortcut: "Ctrl+L" + onTriggered: { + addressBar.forceActiveFocus(); + addressBar.selectAll(); + } + } + Action { + shortcut: StandardKey.Refresh + onTriggered: { + if (currentWebView) + currentWebView.reload(); + } + } + Action { + shortcut: StandardKey.AddTab + onTriggered: { + tabBar.createTab(tabBar.count != 0 ? currentWebView.profile : defaultProfile); + addressBar.forceActiveFocus(); + addressBar.selectAll(); + } + } + Action { + shortcut: StandardKey.Close + onTriggered: { + currentWebView.triggerWebAction(WebEngineView.RequestClose); + } + } + Action { + shortcut: StandardKey.Quit + onTriggered: browserWindow.close() + } + Action { + shortcut: "Escape" + onTriggered: { + if (currentWebView.state == "FullScreen") { + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); + currentWebView.triggerWebAction(WebEngineView.ExitFullScreen); + } + + if (findBar.visible) + findBar.visible = false; + } + } + Action { + shortcut: "Ctrl+0" + onTriggered: currentWebView.zoomFactor = 1.0 + } + Action { + shortcut: StandardKey.ZoomOut + onTriggered: currentWebView.zoomFactor -= 0.1 + } + Action { + shortcut: StandardKey.ZoomIn + onTriggered: currentWebView.zoomFactor += 0.1 + } + + Action { + shortcut: StandardKey.Copy + onTriggered: currentWebView.triggerWebAction(WebEngineView.Copy) + } + Action { + shortcut: StandardKey.Cut + onTriggered: currentWebView.triggerWebAction(WebEngineView.Cut) + } + Action { + shortcut: StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.Paste) + } + Action { + shortcut: "Shift+"+StandardKey.Paste + onTriggered: currentWebView.triggerWebAction(WebEngineView.PasteAndMatchStyle) + } + Action { + shortcut: StandardKey.SelectAll + onTriggered: currentWebView.triggerWebAction(WebEngineView.SelectAll) + } + Action { + shortcut: StandardKey.Undo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Undo) + } + Action { + shortcut: StandardKey.Redo + onTriggered: currentWebView.triggerWebAction(WebEngineView.Redo) + } + Action { + shortcut: StandardKey.Back + onTriggered: currentWebView.triggerWebAction(WebEngineView.Back) + } + Action { + shortcut: StandardKey.Forward + onTriggered: currentWebView.triggerWebAction(WebEngineView.Forward) + } + Action { + shortcut: StandardKey.Find + onTriggered: { + if (!findBar.visible) + findBar.visible = true; + } + } + Action { + shortcut: StandardKey.FindNext + onTriggered: findBar.findNext() + } + Action { + shortcut: StandardKey.FindPrevious + onTriggered: findBar.findPrevious() + } + + menuBar: ToolBar { + id: navigationBar + RowLayout { + anchors.fill: parent + ToolButton { + enabled: currentWebView && (currentWebView.canGoBack || currentWebView.canGoForward) + onClicked: historyMenu.open() + text: qsTr("▼") + Menu { + id: historyMenu + Instantiator { + model: currentWebView && currentWebView.history.items + MenuItem { + text: model.title + onTriggered: currentWebView.goBackOrForward(model.offset) + checkable: !enabled + checked: !enabled + enabled: model.offset + } + + onObjectAdded: function(index, object) { + historyMenu.insertItem(index, object) + } + onObjectRemoved: function(index, object) { + historyMenu.removeItem(object) + } + } + } + } + + ToolButton { + id: backButton + icon.source: "qrc:/icons/go-previous.png" + onClicked: currentWebView.goBack() + enabled: currentWebView && currentWebView.canGoBack + activeFocusOnTab: !browserWindow.platformIsMac + } + ToolButton { + id: forwardButton + icon.source: "qrc:/icons/go-next.png" + onClicked: currentWebView.goForward() + enabled: currentWebView && currentWebView.canGoForward + activeFocusOnTab: !browserWindow.platformIsMac + } + ToolButton { + id: reloadButton + icon.source: currentWebView && currentWebView.loading ? "qrc:/icons/process-stop.png" : "qrc:/icons/view-refresh.png" + onClicked: currentWebView && currentWebView.loading ? currentWebView.stop() : currentWebView.reload() + activeFocusOnTab: !browserWindow.platformIsMac + } + TextField { + id: addressBar + Image { + anchors.verticalCenter: addressBar.verticalCenter; + x: 5 + z: 2 + id: faviconImage + width: 16; height: 16 + sourceSize: Qt.size(width, height) + source: currentWebView && currentWebView.icon ? currentWebView.icon : '' + } + MouseArea { + id: textFieldMouseArea + acceptedButtons: Qt.RightButton + anchors.fill: parent + onClicked: { + var textSelectionStartPos = addressBar.selectionStart; + var textSelectionEndPos = addressBar.selectionEnd; + textFieldContextMenu.open(); + addressBar.select(textSelectionStartPos, textSelectionEndPos); + } + Menu { + id: textFieldContextMenu + x: textFieldMouseArea.mouseX + y: textFieldMouseArea.mouseY + MenuItem { + text: qsTr("Cut") + onTriggered: addressBar.cut() + enabled: addressBar.selectedText.length > 0 + } + MenuItem { + text: qsTr("Copy") + onTriggered: addressBar.copy() + enabled: addressBar.selectedText.length > 0 + } + MenuItem { + text: qsTr("Paste") + onTriggered: addressBar.paste() + enabled: addressBar.canPaste + } + MenuItem { + text: qsTr("Delete") + onTriggered: addressBar.text = qsTr("") + enabled: addressBar.selectedText.length > 0 + } + MenuSeparator {} + MenuItem { + text: qsTr("Select All") + onTriggered: addressBar.selectAll() + enabled: addressBar.text.length > 0 + } + } + } + leftPadding: 26 + focus: true + Layout.fillWidth: true + Binding on text { + when: currentWebView + value: currentWebView.url + } + onAccepted: currentWebView.url = utils.fromUserInput(text) + selectByMouse: true + } + ToolButton { + id: settingsMenuButton + text: qsTr("⋮") + onClicked: settingsMenu.open() + Menu { + id: settingsMenu + y: settingsMenuButton.height + MenuItem { + id: loadImages + text: "Autoload images" + checkable: true + checked: WebEngine.settings.autoLoadImages + } + MenuItem { + id: javaScriptEnabled + text: "JavaScript On" + checkable: true + checked: WebEngine.settings.javascriptEnabled + } + MenuItem { + id: errorPageEnabled + text: "ErrorPage On" + checkable: true + checked: WebEngine.settings.errorPageEnabled + } + MenuItem { + id: pluginsEnabled + text: "Plugins On" + checkable: true + checked: true + } + MenuItem { + id: fullScreenSupportEnabled + text: "FullScreen On" + checkable: true + checked: WebEngine.settings.fullScreenSupportEnabled + } + MenuItem { + id: offTheRecordEnabled + text: "Off The Record" + checkable: true + checked: currentWebView && currentWebView.profile === otrProfile + onToggled: function(checked) { + if (currentWebView) { + currentWebView.profile = checked ? otrProfile : defaultProfile; + } + } + } + MenuItem { + id: httpDiskCacheEnabled + text: "HTTP Disk Cache" + checkable: currentWebView && !currentWebView.profile.offTheRecord + checked: currentWebView && (currentWebView.profile.httpCacheType === WebEngineProfile.DiskHttpCache) + onToggled: function(checked) { + if (currentWebView) { + currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache; + } + } + } + MenuItem { + id: autoLoadIconsForPage + text: "Icons On" + checkable: true + checked: WebEngine.settings.autoLoadIconsForPage + } + MenuItem { + id: touchIconsEnabled + text: "Touch Icons On" + checkable: true + checked: WebEngine.settings.touchIconsEnabled + enabled: autoLoadIconsForPage.checked + } + MenuItem { + id: webRTCPublicInterfacesOnly + text: "WebRTC Public Interfaces Only" + checkable: true + checked: WebEngine.settings.webRTCPublicInterfacesOnly + } + MenuItem { + id: devToolsEnabled + text: "Open DevTools" + checkable: true + checked: false + } + MenuItem { + id: pdfViewerEnabled + text: "PDF viewer enabled" + checkable: true + checked: WebEngine.settings.pdfViewerEnabled + } + } + } + } + ProgressBar { + id: progressBar + height: 3 + anchors { + left: parent.left + top: parent.bottom + right: parent.right + leftMargin: parent.leftMargin + rightMargin: parent.rightMargin + } + background: Item {} + z: -2 + from: 0 + to: 100 + value: (currentWebView && currentWebView.loadProgress < 100) ? currentWebView.loadProgress : 0 + } + } + + StackLayout { + id: tabLayout + currentIndex: tabBar.currentIndex + + anchors.top: tabBar.bottom + anchors.bottom: devToolsView.top + anchors.left: parent.left + anchors.right: parent.right + } + + Component { + id: tabButtonComponent + + TabButton { + property color frameColor: "#999" + property color fillColor: "#eee" + property color nonSelectedColor: "#ddd" + property string tabTitle: "New Tab" + + id: tabButton + contentItem: Rectangle { + id: tabRectangle + color: tabButton.down ? fillColor : nonSelectedColor + border.width: 1 + border.color: frameColor + implicitWidth: Math.max(text.width + 30, 80) + implicitHeight: Math.max(text.height + 10, 20) + Rectangle { height: 1 ; width: parent.width ; color: frameColor} + Rectangle { height: parent.height ; width: 1; color: frameColor} + Rectangle { x: parent.width - 2; height: parent.height ; width: 1; color: frameColor} + Text { + id: text + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + anchors.leftMargin: 6 + text: tabButton.tabTitle + elide: Text.ElideRight + color: tabButton.down ? "black" : frameColor + width: parent.width - button.background.width + } + Button { + id: button + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + anchors.rightMargin: 4 + height: 12 + background: Rectangle { + implicitWidth: 12 + implicitHeight: 12 + color: button.hovered ? "#ccc" : tabRectangle.color + Text {text: "x"; anchors.centerIn: parent; color: "gray"} + } + onClicked: tabButton.closeTab() + } + } + + onClicked: addressBar.text = tabLayout.itemAt(TabBar.index).url; + function closeTab() { + tabBar.removeView(TabBar.index); + } + } + } + + TabBar { + id: tabBar + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + Component.onCompleted: createTab(defaultProfile) + + function createTab(profile, focusOnNewTab = true, url = undefined) { + var webview = tabComponent.createObject(tabLayout, {profile: profile}); + var newTabButton = tabButtonComponent.createObject(tabBar, {tabTitle: Qt.binding(function () { return webview.title; })}); + tabBar.addItem(newTabButton); + if (focusOnNewTab) { + tabBar.setCurrentIndex(tabBar.count - 1); + } + if (url !== undefined) { + webview.url = url; + } + return webview; + } + + function removeView(index) { + tabBar.removeItem(index); + if (tabBar.count > 1) { + tabBar.removeItem(tabBar.itemAt(index)); + tabLayout.children[index].destroy(); + } else { + browserWindow.close(); + } + } + + Component { + id: tabComponent + WebEngineView { + id: webEngineView + focus: true + + onLinkHovered: function(hoveredUrl) { + if (hoveredUrl == "") + hideStatusText.start(); + else { + statusText.text = hoveredUrl; + statusBubble.visible = true; + hideStatusText.stop(); + } + } + + states: [ + State { + name: "FullScreen" + PropertyChanges { + target: tabBar + visible: false + height: 0 + } + PropertyChanges { + target: navigationBar + visible: false + } + } + ] + settings.autoLoadImages: appSettings.autoLoadImages + settings.javascriptEnabled: appSettings.javaScriptEnabled + settings.errorPageEnabled: appSettings.errorPageEnabled + settings.pluginsEnabled: appSettings.pluginsEnabled + settings.fullScreenSupportEnabled: appSettings.fullScreenSupportEnabled + settings.autoLoadIconsForPage: appSettings.autoLoadIconsForPage + settings.touchIconsEnabled: appSettings.touchIconsEnabled + settings.webRTCPublicInterfacesOnly: appSettings.webRTCPublicInterfacesOnly + settings.pdfViewerEnabled: appSettings.pdfViewerEnabled + + onCertificateError: function(error) { + error.defer(); + sslDialog.enqueue(error); + } + + onNewWindowRequested: function(request) { + if (!request.userInitiated) + console.warn("Blocked a popup window."); + else if (request.destination === WebEngineNewWindowRequest.InNewTab) { + var tab = tabBar.createTab(currentWebView.profile, true, request.requestedUrl); + tab.acceptAsNewWindow(request); + } else if (request.destination === WebEngineNewWindowRequest.InNewBackgroundTab) { + var backgroundTab = tabBar.createTab(currentWebView.profile, false); + backgroundTab.acceptAsNewWindow(request); + } else if (request.destination === WebEngineNewWindowRequest.InNewDialog) { + var dialog = applicationRoot.createDialog(currentWebView.profile); + dialog.currentWebView.acceptAsNewWindow(request); + } else { + var window = applicationRoot.createWindow(currentWebView.profile); + window.currentWebView.acceptAsNewWindow(request); + } + } + + onFullScreenRequested: function(request) { + if (request.toggleOn) { + webEngineView.state = "FullScreen"; + browserWindow.previousVisibility = browserWindow.visibility; + browserWindow.showFullScreen(); + fullScreenNotification.show(); + } else { + webEngineView.state = ""; + browserWindow.visibility = browserWindow.previousVisibility; + fullScreenNotification.hide(); + } + request.accept(); + } + + onQuotaRequested: function(request) { + if (request.requestedSize <= 5 * 1024 * 1024) + request.accept(); + else + request.reject(); + } + + onRegisterProtocolHandlerRequested: function(request) { + console.log("accepting registerProtocolHandler request for " + + request.scheme + " from " + request.origin); + request.accept(); + } + + onRenderProcessTerminated: function(terminationStatus, exitCode) { + var status = ""; + switch (terminationStatus) { + case WebEngineView.NormalTerminationStatus: + status = "(normal exit)"; + break; + case WebEngineView.AbnormalTerminationStatus: + status = "(abnormal exit)"; + break; + case WebEngineView.CrashedTerminationStatus: + status = "(crashed)"; + break; + case WebEngineView.KilledTerminationStatus: + status = "(killed)"; + break; + } + + print("Render process exited with code " + exitCode + " " + status); + reloadTimer.running = true; + } + + onSelectClientCertificate: function(selection) { + selection.certificates[0].select(); + } + + onFindTextFinished: function(result) { + if (!findBar.visible) + findBar.visible = true; + + findBar.numberOfMatches = result.numberOfMatches; + findBar.activeMatch = result.activeMatch; + } + + onLoadingChanged: function(loadRequest) { + if (loadRequest.status == WebEngineView.LoadStartedStatus) + findBar.reset(); + } + + Timer { + id: reloadTimer + interval: 0 + running: false + repeat: false + onTriggered: currentWebView.reload() + } + } + } + } + WebEngineView { + id: devToolsView + visible: devToolsEnabled.checked + height: visible ? 400 : 0 + inspectedView: visible && tabBar.currentIndex < tabBar.count ? tabLayout.children[tabBar.currentIndex] : null + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + onNewWindowRequested: function(request) { + var tab = tabBar.createTab(currentWebView.profile); + request.openIn(tab); + } + + Timer { + id: hideTimer + interval: 0 + running: false + repeat: false + onTriggered: devToolsEnabled.checked = false + } + onWindowCloseRequested: function(request) { + // Delay hiding for keep the inspectedView set to receive the ACK message of close. + hideTimer.running = true; + } + } + Dialog { + id: sslDialog + anchors.centerIn: parent + contentWidth: Math.max(mainText.width, detailedText.width) + contentHeight: mainText.height + detailedText.height + property var certErrors: [] + // fixme: icon! + // icon: StandardIcon.Warning + standardButtons: Dialog.No | Dialog.Yes + title: "Server's certificate not trusted" + contentItem: Item { + id: textContentItem + Label { + id: mainText + text: "Do you wish to continue?" + } + Text { + id: detailedText + anchors.top: mainText.bottom + text: "If you wish so, you may continue with an unverified certificate.\n" + + "Accepting an unverified certificate means\n" + + "you may not be connected with the host you tried to connect to.\n" + + "Do you wish to override the security check and continue?" + } + } + + onAccepted: { + certErrors.shift().acceptCertificate(); + presentError(); + } + onRejected: reject() + + function reject(){ + certErrors.shift().rejectCertificate(); + presentError(); + } + function enqueue(error){ + certErrors.push(error); + presentError(); + } + function presentError(){ + visible = certErrors.length > 0 + } + } + + FullScreenNotification { + id: fullScreenNotification + } + + DownloadView { + id: downloadView + visible: false + anchors.fill: parent + } + + function onDownloadRequested(download) { + downloadView.visible = true; + downloadView.append(download); + download.accept(); + } + + FindBar { + id: findBar + visible: false + anchors.right: parent.right + anchors.rightMargin: 10 + anchors.top: parent.top + + onFindNext: { + if (text) + currentWebView && currentWebView.findText(text); + else if (!visible) + visible = true; + } + onFindPrevious: { + if (text) + currentWebView && currentWebView.findText(text, WebEngineView.FindBackward); + else if (!visible) + visible = true; + } + } + + + Rectangle { + id: statusBubble + color: "oldlace" + property int padding: 8 + visible: false + + anchors.left: parent.left + anchors.bottom: parent.bottom + width: statusText.paintedWidth + padding + height: statusText.paintedHeight + padding + + Text { + id: statusText + anchors.centerIn: statusBubble + elide: Qt.ElideMiddle + + Timer { + id: hideStatusText + interval: 750 + onTriggered: { + statusText.text = ""; + statusBubble.visible = false; + } + } + } + } +} diff --git a/examples/webenginequick/quicknanobrowser/CMakeLists.txt b/examples/webenginequick/quicknanobrowser/CMakeLists.txt new file mode 100644 index 000000000..a9e8bb4ae --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/CMakeLists.txt @@ -0,0 +1,81 @@ +cmake_minimum_required(VERSION 3.16) +project(quicknanobrowser LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/webenginequick/quicknanobrowser") + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Gui) +find_package(Qt6 COMPONENTS Qml) +find_package(Qt6 COMPONENTS Quick) +find_package(Qt6 COMPONENTS WebEngineQuick) + +qt_add_executable(quicknanobrowser + main.cpp + utils.h +) +set_target_properties(quicknanobrowser PROPERTIES + WIN32_EXECUTABLE TRUE + MACOSX_BUNDLE TRUE +) +target_link_libraries(quicknanobrowser PUBLIC + Qt::Core + Qt::Gui + Qt::Qml + Qt::Quick + Qt::WebEngineQuick +) + + +# Resources: +set(resources_resource_files + "ApplicationRoot.qml" + "BrowserDialog.qml" + "BrowserWindow.qml" + "DownloadView.qml" + "FindBar.qml" + "FullScreenNotification.qml" +) + +qt6_add_resources(quicknanobrowser "resources" + PREFIX + "/" + FILES + ${resources_resource_files} +) +set(resources1_resource_files + "icons/3rdparty/go-next.png" + "icons/3rdparty/go-previous.png" + "icons/3rdparty/process-stop.png" + "icons/3rdparty/view-refresh.png" +) + +qt6_add_resources(quicknanobrowser "resources1" + PREFIX + "/icons" + BASE + "icons/3rdparty" + FILES + ${resources1_resource_files} +) + +if(TARGET Qt::Widgets) + target_link_libraries(quicknanobrowser PUBLIC + Qt::Widgets + ) +endif() + +install(TARGETS quicknanobrowser + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/webenginequick/quicknanobrowser/DownloadView.qml b/examples/webenginequick/quicknanobrowser/DownloadView.qml new file mode 100644 index 000000000..ea7e0b53d --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/DownloadView.qml @@ -0,0 +1,174 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Controls +import QtWebEngine +import QtQuick.Layouts + +Rectangle { + id: downloadView + color: "lightgray" + + ListModel { + id: downloadModel + property var downloads: [] + } + + function append(download) { + downloadModel.append(download); + downloadModel.downloads.push(download); + } + + Component { + id: downloadItemDelegate + + Rectangle { + width: listView.width + height: childrenRect.height + anchors.margins: 10 + radius: 3 + color: "transparent" + border.color: "black" + Rectangle { + id: progressBar + + property real progress: downloadModel.downloads[index] + ? downloadModel.downloads[index].receivedBytes / downloadModel.downloads[index].totalBytes : 0 + + radius: 3 + color: width == listView.width ? "green" : "#2b74c7" + width: listView.width * progress + height: cancelButton.height + + Behavior on width { + SmoothedAnimation { duration: 100 } + } + } + Rectangle { + anchors { + left: parent.left + right: parent.right + leftMargin: 20 + } + Label { + id: label + text: downloadModel.downloads[index] ? downloadModel.downloads[index].downloadDirectory + "/" + downloadModel.downloads[index].downloadFileName : qsTr("") + anchors { + verticalCenter: cancelButton.verticalCenter + left: parent.left + right: cancelButton.left + } + } + Button { + id: cancelButton + anchors.right: parent.right + icon.source: "qrc:/icons/process-stop.png" + onClicked: { + var download = downloadModel.downloads[index]; + + download.cancel(); + + downloadModel.downloads = downloadModel.downloads.filter(function (el) { + return el.id !== download.id; + }); + downloadModel.remove(index); + } + } + } + } + + } + ListView { + id: listView + anchors { + topMargin: 10 + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + width: parent.width - 20 + spacing: 5 + + model: downloadModel + delegate: downloadItemDelegate + + Text { + visible: !listView.count + horizontalAlignment: Text.AlignHCenter + height: 30 + anchors { + top: parent.top + left: parent.left + right: parent.right + } + font.pixelSize: 20 + text: "No active downloads." + } + + Rectangle { + color: "gray" + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + height: 30 + Button { + id: okButton + text: "OK" + anchors.centerIn: parent + onClicked: { + downloadView.visible = false; + } + } + } + } +} diff --git a/examples/webenginequick/quicknanobrowser/FindBar.qml b/examples/webenginequick/quicknanobrowser/FindBar.qml new file mode 100644 index 000000000..738a38c84 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/FindBar.qml @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts + +Rectangle { + id: root + + property int numberOfMatches: 0 + property int activeMatch: 0 + property alias text: findTextField.text + + function reset() { + numberOfMatches = 0; + activeMatch = 0; + visible = false; + } + + signal findNext() + signal findPrevious() + + width: 250 + height: 35 + radius: 2 + + border.width: 1 + border.color: "black" + color: "white" + + onVisibleChanged: { + if (visible) + findTextField.forceActiveFocus(); + } + + + RowLayout { + anchors.fill: parent + anchors.topMargin: 5 + anchors.bottomMargin: 5 + anchors.leftMargin: 10 + anchors.rightMargin: 10 + + spacing: 5 + + Rectangle { + Layout.fillWidth: true + Layout.fillHeight: true + + TextField { + id: findTextField + anchors.fill: parent + background: Rectangle { + color: "transparent" + } + + onAccepted: root.findNext() + onTextChanged: root.findNext() + onActiveFocusChanged: activeFocus ? selectAll() : deselect() + } + } + + Label { + text: activeMatch + "/" + numberOfMatches + visible: findTextField.text != "" + } + + Rectangle { + border.width: 1 + border.color: "#ddd" + width: 2 + height: parent.height + anchors.topMargin: 5 + anchors.bottomMargin: 5 + } + + ToolButton { + text: "<" + enabled: numberOfMatches > 0 + onClicked: root.findPrevious() + } + + ToolButton { + text: ">" + enabled: numberOfMatches > 0 + onClicked: root.findNext() + } + + ToolButton { + text: "x" + onClicked: root.visible = false + } + } +} diff --git a/examples/webenginequick/quicknanobrowser/FullScreenNotification.qml b/examples/webenginequick/quicknanobrowser/FullScreenNotification.qml new file mode 100644 index 000000000..c5f891db6 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/FullScreenNotification.qml @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick + +Rectangle { + id: fullScreenNotification + width: 500 + height: 40 + color: "white" + radius: 7 + + visible: false + opacity: 0 + + function show() { + visible = true; + opacity = 1; + reset.start(); + } + + function hide() { + reset.stop(); + opacity = 0; + } + + Behavior on opacity { + NumberAnimation { + duration: 750 + onStopped: { + if (opacity == 0) + visible = false; + } + } + } + + Timer { + id: reset + interval: 5000 + onTriggered: hide() + } + + anchors.horizontalCenter: parent.horizontalCenter + y: 125 + + Text { + id: message + width: parent.width + + anchors.horizontalCenter: parent.horizontalCenter + anchors.verticalCenter: parent.verticalCenter + + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + + wrapMode: Text.WordWrap + elide: Text.ElideNone + clip: true + + text: qsTr("You are now in fullscreen mode. Press ESC to quit!") + } +} diff --git a/examples/webenginequick/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg b/examples/webenginequick/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg Binary files differnew file mode 100644 index 000000000..12693bb0f --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/doc/images/quicknanobrowser-demo.jpg diff --git a/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc new file mode 100644 index 000000000..3b9af68b2 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/doc/src/quicknanobrowser.qdoc @@ -0,0 +1,153 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example webenginequick/quicknanobrowser + \title WebEngine Quick Nano Browser + \ingroup webengine-examples + \brief A web browser implemented using the WebEngineView QML type. + + \image quicknanobrowser-demo.jpg + + \e {Quick Nano Browser} demonstrates how to use the \l{Qt WebEngine QML Types} + {Qt WebEngine QML types} to develop a small web browser application that consists of a browser + window with a title bar, toolbar, tab view, and status bar. The web content is loaded in a web + engine view within the tab view. If certificate errors occur, users are prompted for action in a + message dialog. The status bar pops up to display the URL of a hovered link. + + A web page can issue a request for being displayed in fullscreen mode. Users can allow full + screen mode by using a toolbar button. They can leave fullscreen mode by using a keyboard + shortcut. Additional toolbar buttons enable moving backwards and forwards in the browser + history, reloading tab content, and opening a settings menu for enabling the following features: + JavaScript, plugins, fullscreen mode, off the record, HTTP disk cache, autoloading images, and + ignoring certificate errors. + + \include examples-run.qdocinc + + \section1 Creating the Main Browser Window + + When the browser main window is loaded, it creates an empty tab using the default profile. Each + tab is a web engine view that fills the main window. + + We create the main window in the \e BrowserWindow.qml file using the ApplicationWindow type: + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto ApplicationWindow + \printuntil currentWebView + \dots + \skipto width + \printuntil title + + We use the TabBar Qt Quick control to create a tab bar anchored to the top of the window, and + create a new, empty tab: + + \skipto TabBar { + \printuntil return webview + \printuntil } + + The tab contains a web engine view that loads web content: + + \skipto Component { + \printuntil currentWebView.reload + \printuntil /^\ {8}\}/ + + We use the \l Action type to create new tabs: + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto reload + \skipto Action + \printuntil } + + We use the \l TextField Qt Quick Control within a \l ToolBar to create an address bar that + shows the current URL and where users can enter another URL: + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto menuBar: ToolBar + \printuntil anchors.fill + \dots + \skipto TextField + \printuntil addressBar + \dots + \skipto focus + \printuntil /^\ {12}\}/ + + \section1 Handling Certificate Errors + + If the certificate of the site being loaded triggers a certificate error, we call the + \l{WebEngineCertificateError::}{defer()} QML method to pause the URL request and wait for user + input: + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto onCertificateError + \printuntil } + + We use the Dialog type to prompt users to continue or cancel the loading of the web page. + If users select \uicontrol Yes, we call the + \l{WebEngineCertificateError::}{acceptCertificate()} method to continue loading content from + the URL. If users select \uicontrol No, we call the + \l{WebEngineCertificateError::}{rejectCertificate()} method to reject the request and stop + loading content from the URL: + + \skipto Dialog { + \printuntil /^\ {4}\}/ + + \section1 Entering and Leaving Fullscreen Mode + + We create a menu item for allowing fullscreen mode in a settings menu that we place on the tool + bar. Also, we create an action for leaving fullscreen mode by using a keyboard shortcut. + We call the \l{FullScreenRequest::}{accept()} method to accept the fullscreen request. + The methdod sets the \l{WebEngineView::}{isFullScreen} property to be equal to the + \l{FullScreenRequest::}{toggleOn} property. + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto onFullScreenRequested + \printuntil /^\ {16}\}/ + + When entering fullscreen mode, we display a notification using the FullScreenNotification custom + type that we create in \e FullScreenNotification.qml. + + We use the \l Action type in the settings menu to create a shortcut for leaving fullscreen mode + by pressing the escape key: + + \quotefromfile webenginequick/quicknanobrowser/BrowserWindow.qml + \skipto Settings + \printuntil appSettings + \skipto fullScreenSupportEnabled + \printuntil Action + \skipto Escape + \printuntil /^\ {4}\}/ + + \section1 Files and Attributions + + The example uses icons from the Tango Icon Library: + + \table + \row + \li \l{quicknanobrowser-tango}{Tango Icon Library} + \li Public Domain + \endtable +*/ diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/COPYING b/examples/webenginequick/quicknanobrowser/icons/3rdparty/COPYING new file mode 100644 index 000000000..220881da6 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/COPYING @@ -0,0 +1 @@ +The icons in this repository are herefore released into the Public Domain. diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-next.png b/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-next.png Binary files differnew file mode 100644 index 000000000..6f3f65d33 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-next.png diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-previous.png b/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-previous.png Binary files differnew file mode 100644 index 000000000..93be3d1ee --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/go-previous.png diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/process-stop.png b/examples/webenginequick/quicknanobrowser/icons/3rdparty/process-stop.png Binary files differnew file mode 100644 index 000000000..b68290bf1 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/process-stop.png diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/qt_attribution.json b/examples/webenginequick/quicknanobrowser/icons/3rdparty/qt_attribution.json new file mode 100644 index 000000000..4e5a44448 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/qt_attribution.json @@ -0,0 +1,24 @@ +{ + "Id": "quicknanobrowser-tango", + "Name": "Tango Icon Library", + "QDocModule": "qtwebengine", + "QtUsage": "Used in WebEngine Quick Nano Browser example.", + + "QtParts": [ "examples" ], + "Description": "Selected icons from the Tango Icon Library", + "Homepage": "http://tango.freedesktop.org/Tango_Icon_Library", + "Version": "0.8.90", + "DownloadLocation": "http://tango.freedesktop.org/releases/tango-icon-theme-0.8.90.tar.gz", + "LicenseId": "DocumentRef-PublicDomain", + "License": "Public Domain", + "LicenseFile": "COPYING", + "Copyright": "Ulisse Perusin <uli.peru@gmail.com> +Steven Garrity <sgarrity@silverorange.com> +Lapo Calamandrei <calamandrei@gmail.com> +Ryan Collier <rcollier@novell.com> +Rodney Dawes <dobey@novell.com> +Andreas Nilsson <nisses.mail@home.se> +Tuomas Kuosmanen <tigert@tigert.com> +Garrett LeSage <garrett@novell.com> +Jakub Steiner <jimmac@novell.com>" +} diff --git a/examples/webenginequick/quicknanobrowser/icons/3rdparty/view-refresh.png b/examples/webenginequick/quicknanobrowser/icons/3rdparty/view-refresh.png Binary files differnew file mode 100644 index 000000000..cab4d02c7 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/icons/3rdparty/view-refresh.png diff --git a/examples/webenginequick/quicknanobrowser/main.cpp b/examples/webenginequick/quicknanobrowser/main.cpp new file mode 100644 index 000000000..859856d92 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/main.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "utils.h" + +#ifndef QT_NO_WIDGETS +#include <QtWidgets/QApplication> +typedef QApplication Application; +#else +#include <QtGui/QGuiApplication> +typedef QGuiApplication Application; +#endif +#include <QtQml/QQmlApplicationEngine> +#include <QtQml/QQmlContext> +#include <QtWebEngineQuick/qtwebenginequickglobal.h> + +static QUrl startupUrl() +{ + QUrl ret; + QStringList args(qApp->arguments()); + args.takeFirst(); + for (const QString &arg : qAsConst(args)) { + if (arg.startsWith(QLatin1Char('-'))) + continue; + ret = Utils::fromUserInput(arg); + if (ret.isValid()) + return ret; + } + return QUrl(QStringLiteral("https://www.qt.io")); +} + +int main(int argc, char **argv) +{ + QCoreApplication::setOrganizationName("QtExamples"); + QtWebEngineQuick::initialize(); + + Application app(argc, argv); + + QQmlApplicationEngine appEngine; + Utils utils; + appEngine.rootContext()->setContextProperty("utils", &utils); + appEngine.load(QUrl("qrc:/ApplicationRoot.qml")); + if (!appEngine.rootObjects().isEmpty()) + QMetaObject::invokeMethod(appEngine.rootObjects().first(), "load", Q_ARG(QVariant, startupUrl())); + else + qFatal("Failed to load sources"); + + return app.exec(); +} diff --git a/examples/webenginequick/quicknanobrowser/quicknanobrowser.pro b/examples/webenginequick/quicknanobrowser/quicknanobrowser.pro new file mode 100644 index 000000000..8208e446a --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/quicknanobrowser.pro @@ -0,0 +1,25 @@ +requires(qtConfig(accessibility)) + +TEMPLATE = app +TARGET = quicknanobrowser + +HEADERS = utils.h +SOURCES = main.cpp + +OTHER_FILES += ApplicationRoot.qml \ + BrowserDialog.qml \ + BrowserWindow.qml \ + DownloadView.qml \ + FindBar.qml \ + FullScreenNotification.qml + +RESOURCES += resources.qrc + +QT += qml quick webenginequick + +qtHaveModule(widgets) { + QT += widgets # QApplication is required to get native styling with QtQuickControls +} + +target.path = $$[QT_INSTALL_EXAMPLES]/webenginequick/quicknanobrowser +INSTALLS += target diff --git a/examples/webenginequick/quicknanobrowser/resources.qrc b/examples/webenginequick/quicknanobrowser/resources.qrc new file mode 100644 index 000000000..9d1f927d3 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/resources.qrc @@ -0,0 +1,16 @@ +<RCC> + <qresource prefix="/"> + <file>ApplicationRoot.qml</file> + <file>BrowserDialog.qml</file> + <file>BrowserWindow.qml</file> + <file>DownloadView.qml</file> + <file>FindBar.qml</file> + <file>FullScreenNotification.qml</file> + </qresource> + <qresource prefix="/icons"> + <file alias="go-next.png">icons/3rdparty/go-next.png</file> + <file alias="go-previous.png">icons/3rdparty/go-previous.png</file> + <file alias="process-stop.png">icons/3rdparty/process-stop.png</file> + <file alias="view-refresh.png">icons/3rdparty/view-refresh.png</file> + </qresource> +</RCC> diff --git a/examples/webenginequick/quicknanobrowser/utils.h b/examples/webenginequick/quicknanobrowser/utils.h new file mode 100644 index 000000000..79aa38cc7 --- /dev/null +++ b/examples/webenginequick/quicknanobrowser/utils.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef UTILS_H +#define UTILS_H + +#include <QtCore/QFileInfo> +#include <QtCore/QUrl> + +class Utils : public QObject { + Q_OBJECT +public: + Q_INVOKABLE static QUrl fromUserInput(const QString& userInput); +}; + +inline QUrl Utils::fromUserInput(const QString& userInput) +{ + QFileInfo fileInfo(userInput); + if (fileInfo.exists()) + return QUrl::fromLocalFile(fileInfo.absoluteFilePath()); + return QUrl::fromUserInput(userInput); +} + +#endif // UTILS_H |