summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/webengine/lifecycle/WebBrowser.qml172
-rw-r--r--examples/webengine/lifecycle/WebTab.qml212
-rw-r--r--examples/webengine/lifecycle/WebTabBar.qml100
-rw-r--r--examples/webengine/lifecycle/WebTabButton.qml158
-rw-r--r--examples/webengine/lifecycle/WebTabStack.qml98
-rw-r--r--examples/webengine/lifecycle/WebToolButton.qml63
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle-automatic.pngbin0 -> 8148 bytes
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle-manual.pngbin0 -> 5855 bytes
-rw-r--r--examples/webengine/lifecycle/doc/images/lifecycle.pngbin0 -> 24494 bytes
-rw-r--r--examples/webengine/lifecycle/doc/src/lifecycle.qdoc167
-rw-r--r--examples/webengine/lifecycle/lifecycle.pro10
-rw-r--r--examples/webengine/lifecycle/main.cpp66
-rw-r--r--examples/webengine/lifecycle/qtquickcontrols2.conf6
-rw-r--r--examples/webengine/lifecycle/resources.qrc11
-rw-r--r--examples/webengine/minimal/main.cpp1
-rw-r--r--examples/webengine/quicknanobrowser/ApplicationRoot.qml2
-rw-r--r--examples/webengine/quicknanobrowser/BrowserWindow.qml59
-rw-r--r--examples/webengine/quicknanobrowser/DownloadView.qml2
-rw-r--r--examples/webengine/quicknanobrowser/FindBar.qml146
-rw-r--r--examples/webengine/quicknanobrowser/quicknanobrowser.pro1
-rw-r--r--examples/webengine/quicknanobrowser/resources.qrc1
-rw-r--r--examples/webengine/webengine.pro1
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.cpp20
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.h1
-rw-r--r--examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp6
-rw-r--r--examples/webenginewidgets/simplebrowser/downloadwidget.cpp5
-rw-r--r--examples/webenginewidgets/simplebrowser/downloadwidget.h4
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp4
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.h1
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp42
-rw-r--r--examples/webenginewidgets/simplebrowser/webpopupwindow.cpp2
31 files changed, 1331 insertions, 30 deletions
diff --git a/examples/webengine/lifecycle/WebBrowser.qml b/examples/webengine/lifecycle/WebBrowser.qml
new file mode 100644
index 000000000..23c2500e2
--- /dev/null
+++ b/examples/webengine/lifecycle/WebBrowser.qml
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtQuick.Window 2.12
+
+ApplicationWindow {
+ id: root
+
+ readonly property Action newTabAction: Action {
+ text: qsTr("New tab")
+ shortcut: StandardKey.AddTab
+ onTriggered: root.createNewTab({url: "about:blank"})
+ }
+
+ visible: true
+ width: Screen.width * 0.5
+ height: Screen.height * 0.5
+ title: tabStack.currentTab ? tabStack.currentTab.title : ""
+
+ header: WebTabBar {
+ id: tabBar
+
+ z: 1
+
+ newTabAction: root.newTabAction
+ }
+
+ WebTabStack {
+ id: tabStack
+
+ z: 0
+ anchors.fill: parent
+
+ currentIndex: tabBar.currentIndex
+ freezeDelay: freezeSpin.enabled && freezeSpin.value
+ discardDelay: discardSpin.enabled && discardSpin.value
+
+ onCloseRequested: function(index) {
+ root.closeTab(index)
+ }
+
+ onDrawerRequested: drawer.toggle()
+ }
+
+ Drawer {
+ id: drawer
+
+ edge: Qt.RightEdge
+ height: root.height
+
+ Control {
+ padding: 16
+ contentItem: ColumnLayout {
+ Label {
+ Layout.alignment: Qt.AlignHCenter
+ text: qsTr("Settings")
+ font.capitalization: Font.AllUppercase
+ }
+ MenuSeparator {}
+ CheckBox {
+ id: lifecycleCheck
+ text: qsTr("Automatic lifecycle control")
+ checked: true
+ }
+ CheckBox {
+ id: freezeCheck
+ text: qsTr("Freeze after delay (seconds)")
+ enabled: lifecycleCheck.checked
+ checked: true
+ }
+ SpinBox {
+ id: freezeSpin
+ editable: true
+ enabled: freezeCheck.checked
+ value: 60
+ from: 1
+ to: 60*60
+ }
+ CheckBox {
+ id: discardCheck
+ text: qsTr("Discard after delay (seconds)")
+ enabled: lifecycleCheck.checked
+ checked: true
+ }
+ SpinBox {
+ id: discardSpin
+ editable: true
+ enabled: discardCheck.checked
+ value: 60*60
+ from: 1
+ to: 60*60
+ }
+ }
+ }
+
+ function toggle() {
+ if (drawer.visible)
+ drawer.close()
+ else
+ drawer.open()
+ }
+ }
+
+ Component.onCompleted: {
+ createNewTab({url: "https://www.qt.io"})
+ }
+
+ function createNewTab(properties) {
+ const tab = tabStack.createNewTab(properties)
+ tabBar.createNewTab({tab: tab})
+ tabBar.currentIndex = tab.index
+ return tab
+ }
+
+ function closeTab(index) {
+ if (tabStack.count == 1)
+ Qt.quit()
+ tabBar.closeTab(index)
+ tabStack.closeTab(index)
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTab.qml b/examples/webengine/lifecycle/WebTab.qml
new file mode 100644
index 000000000..645758104
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTab.qml
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QtQml 2.12
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtWebEngine 1.11
+
+ColumnLayout {
+ id: root
+
+ signal closeRequested
+ signal drawerRequested
+
+ property int freezeDelay
+ property int discardDelay
+
+ property alias icon : view.icon
+ property alias loading : view.loading
+ property alias url : view.url
+ property alias lifecycleState : view.lifecycleState
+ property alias recommendedState : view.recommendedState
+
+ readonly property string title : {
+ if (view.url == "about:blank")
+ return qsTr("New tab")
+ if (view.title)
+ return view.title
+ return view.url
+ }
+
+ readonly property Action backAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Back)
+ enabled: webAction.enabled
+ text: qsTr("Back")
+ shortcut: root.visible && StandardKey.Back
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action forwardAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Forward)
+ enabled: webAction.enabled
+ text: qsTr("Forward")
+ shortcut: root.visible && StandardKey.Forward
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action reloadAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Reload)
+ enabled: webAction.enabled
+ text: qsTr("Reload")
+ shortcut: root.visible && StandardKey.Refresh
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action stopAction: Action {
+ property WebEngineAction webAction: view.action(WebEngineView.Stop)
+ enabled: webAction.enabled
+ text: qsTr("Stop")
+ shortcut: root.visible && StandardKey.Cancel
+ onTriggered: webAction.trigger()
+ }
+
+ readonly property Action closeAction: Action {
+ text: qsTr("Close")
+ shortcut: root.visible && StandardKey.Close
+ onTriggered: root.closeRequested()
+ }
+
+ readonly property Action activateAction: Action {
+ text: qsTr("Active")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Active
+ enabled: checked || (view.lifecycleState != WebEngineView.LifecycleState.Active)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Active
+ }
+
+ readonly property Action freezeAction: Action {
+ text: qsTr("Frozen")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Frozen
+ enabled: checked || (!view.visible && view.lifecycleState == WebEngineView.LifecycleState.Active)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Frozen
+ }
+
+ readonly property Action discardAction: Action {
+ text: qsTr("Discarded")
+ checkable: true
+ checked: view.lifecycleState == WebEngineView.LifecycleState.Discarded
+ enabled: checked || (!view.visible && view.lifecycleState == WebEngineView.LifecycleState.Frozen)
+ onTriggered: view.lifecycleState = WebEngineView.LifecycleState.Discarded
+ }
+
+ spacing: 0
+
+ ToolBar {
+ Layout.fillWidth: true
+ Material.elevation: 0
+ Material.background: Material.color(Material.Grey, Material.Shade800)
+
+ RowLayout {
+ anchors.fill: parent
+ WebToolButton {
+ action: root.backAction
+ text: "←"
+ ToolTip.text: root.backAction.text
+ }
+ WebToolButton {
+ action: root.forwardAction
+ text: "→"
+ ToolTip.text: root.forwardAction.text
+ }
+ WebToolButton {
+ action: root.reloadAction
+ visible: root.reloadAction.enabled
+ text: "↻"
+ ToolTip.text: root.reloadAction.text
+ }
+ WebToolButton {
+ action: root.stopAction
+ visible: root.stopAction.enabled
+ text: "✕"
+ ToolTip.text: root.stopAction.text
+ }
+ TextField {
+ Layout.fillWidth: true
+ Layout.topMargin: 6
+
+ placeholderText: qsTr("Type a URL")
+ text: view.url == "about:blank" ? "" : view.url
+ selectByMouse: true
+
+ onAccepted: { view.url = text }
+ }
+ WebToolButton {
+ text: "⋮"
+ ToolTip.text: qsTr("Settings")
+ onClicked: root.drawerRequested()
+ }
+ }
+ }
+
+ WebEngineView {
+ id: view
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ }
+
+ Timer {
+ interval: {
+ switch (view.recommendedState) {
+ case WebEngineView.LifecycleState.Active:
+ return 1
+ case WebEngineView.LifecycleState.Frozen:
+ return root.freezeDelay * 1000
+ case WebEngineView.LifecycleState.Discarded:
+ return root.discardDelay * 1000
+ }
+ }
+ running: interval && view.lifecycleState != view.recommendedState
+ onTriggered: view.lifecycleState = view.recommendedState
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabBar.qml b/examples/webengine/lifecycle/WebTabBar.qml
new file mode 100644
index 000000000..326ad39d2
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabBar.qml
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+
+Pane {
+ id: root
+
+ property Action newTabAction
+
+ property alias currentIndex: tabBar.currentIndex
+
+ signal closeRequested(int index)
+
+ Material.background: Material.color(Material.Grey, Material.Shade900)
+ Material.elevation: 4
+ padding: 0
+
+ RowLayout {
+ spacing: 0
+ anchors.fill: parent
+
+ TabBar {
+ id: tabBar
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ }
+
+ WebToolButton {
+ Layout.bottomMargin: 2
+
+ action: root.newTabAction
+ text: "+"
+ ToolTip.text: root.newTabAction.text
+ }
+ }
+
+ Component {
+ id: factory
+ WebTabButton {}
+ }
+
+ function createNewTab(properties) {
+ return factory.createObject(tabBar, properties)
+ }
+
+ function closeTab(index) {
+ tabBar.takeItem(index).destroy()
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabButton.qml b/examples/webengine/lifecycle/WebTabButton.qml
new file mode 100644
index 000000000..815e2fb09
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabButton.qml
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import QtWebEngine 1.11
+
+TabButton {
+ id: root
+
+ property WebTab tab
+
+ text: root.tab.title
+
+ ToolTip.delay: 1000
+ ToolTip.visible: root.hovered
+ ToolTip.text: root.text
+
+ padding: 6
+
+ contentItem: RowLayout {
+ Item {
+ implicitWidth: 16
+ implicitHeight: 16
+ BusyIndicator {
+ visible: root.tab.loading
+ anchors.fill: parent
+ leftInset: 0
+ topInset: 0
+ rightInset: 0
+ bottomInset: 0
+ padding: 0
+ }
+ Image {
+ visible: !root.tab.loading
+ source: root.tab.icon
+ anchors.fill: parent
+ }
+ }
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: 4
+ Layout.rightMargin: 4
+ text: root.text
+ elide: Text.ElideRight
+ color: {
+ switch (root.tab.lifecycleState) {
+ case WebEngineView.LifecycleState.Active:
+ return Material.color(Material.Grey, Material.Shade100)
+ case WebEngineView.LifecycleState.Frozen:
+ return Material.color(Material.Blue, Material.Shade400)
+ case WebEngineView.LifecycleState.Discarded:
+ return Material.color(Material.Red, Material.Shade400)
+ }
+ }
+
+ }
+ WebToolButton {
+ action: root.tab.closeAction
+ text: "✕"
+ ToolTip.text: action.text
+ }
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ propagateComposedEvents: true
+ onClicked: contextMenu.popup()
+ }
+
+ Menu {
+ id: contextMenu
+ Control {
+ contentItem: Label {
+ text: qsTr("Manual lifecycle control")
+ }
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ Repeater {
+ model: [root.tab.activateAction, root.tab.freezeAction, root.tab.discardAction]
+ RadioButton {
+ action: modelData
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ }
+ Control {
+ contentItem: Label {
+ text: qsTr("Recommended: %1").arg(recommendedStateText)
+ property string recommendedStateText: {
+ switch (root.tab.recommendedState) {
+ case WebEngineView.LifecycleState.Active:
+ return root.tab.activateAction.text
+ case WebEngineView.LifecycleState.Frozen:
+ return root.tab.freezeAction.text
+ case WebEngineView.LifecycleState.Discarded:
+ return root.tab.discardAction.text
+ }
+ }
+ color: Material.hintTextColor
+ }
+ font.pointSize: 8
+ verticalPadding: 9
+ horizontalPadding: 14
+ }
+ }
+}
diff --git a/examples/webengine/lifecycle/WebTabStack.qml b/examples/webengine/lifecycle/WebTabStack.qml
new file mode 100644
index 000000000..75cbba861
--- /dev/null
+++ b/examples/webengine/lifecycle/WebTabStack.qml
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 QtQml.Models 2.12
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+Rectangle {
+ id: root
+
+ signal closeRequested(int index)
+ signal drawerRequested
+
+ property int freezeDelay
+ property int discardDelay
+
+ property int currentIndex
+ property var currentTab: model.children[currentIndex]
+ property alias count: model.count
+
+ color: "white"
+
+ ObjectModel {
+ id: model
+ }
+
+ Component {
+ id: factory
+ WebTab {
+ readonly property int index : ObjectModel.index
+ anchors.fill: parent
+ visible: index == root.currentIndex
+ freezeDelay: root.freezeDelay
+ discardDelay: root.discardDelay
+ onCloseRequested: root.closeRequested(index)
+ onDrawerRequested: root.drawerRequested()
+ }
+ }
+
+ function createNewTab(properties) {
+ const tab = factory.createObject(root, properties)
+ model.append(tab)
+ return tab
+ }
+
+ function closeTab(index) {
+ const tab = model.get(index)
+ model.remove(index)
+ tab.destroy()
+ }
+}
diff --git a/examples/webengine/lifecycle/WebToolButton.qml b/examples/webengine/lifecycle/WebToolButton.qml
new file mode 100644
index 000000000..958c083cd
--- /dev/null
+++ b/examples/webengine/lifecycle/WebToolButton.qml
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+
+ToolButton {
+ id: root
+ font.bold: true
+ font.pointSize: 12
+ ToolTip.delay: 1000
+ ToolTip.visible: hovered
+ implicitWidth: 32
+ implicitHeight: 32
+}
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png b/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png
new file mode 100644
index 000000000..2c62967af
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle-automatic.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle-manual.png b/examples/webengine/lifecycle/doc/images/lifecycle-manual.png
new file mode 100644
index 000000000..7fb5c5a80
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle-manual.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/images/lifecycle.png b/examples/webengine/lifecycle/doc/images/lifecycle.png
new file mode 100644
index 000000000..87b719022
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/images/lifecycle.png
Binary files differ
diff --git a/examples/webengine/lifecycle/doc/src/lifecycle.qdoc b/examples/webengine/lifecycle/doc/src/lifecycle.qdoc
new file mode 100644
index 000000000..4151d0597
--- /dev/null
+++ b/examples/webengine/lifecycle/doc/src/lifecycle.qdoc
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 webengine/lifecycle
+ \title WebEngine Lifecycle Example
+ \ingroup webengine-examples
+ \brief Freezes and discards background tabs to reduce CPU and memory usage.
+
+ \image lifecycle.png
+
+ \e {WebEngine Lifecycle Example} demonstrates how the \l
+ {WebEngineView::}{lifecycleState} and \l {WebEngineView::}{recommendedState}
+ properties of the \l {WebEngineView} can be used to reduce the CPU and
+ memory usage of background tabs in a tabbed browser.
+
+ \include examples-run.qdocinc
+
+ \section1 UI Elements of the Example
+
+ The example uses \l {Qt Quick Controls 2} to implement a traditional tabbed
+ browser in the \l {Material Style} (dark variant). The main application
+ window (\c {WebBrowser.qml}) is divided into a header bar at the top and a
+ main viewing area filling the rest of the window. The header contains the
+ tab bar (\c {WebTabBar.qml}) with one button per tab (\c
+ {WebTabButton.qml}). The main area consists of a stack of tabs (\c
+ {WebTabStack.qml} and \c {WebTab.qml}). Each tab in turn has a tool bar at
+ the top and a \l {WebEngineView} for displaying web pages. Finally, the main
+ window also has a \l {Drawer} for changing settings. The drawer can be
+ opened by clicking the "⋮" button on the tool bar.
+
+ \section1 Overview of Lifecycle States
+
+ Each \l {WebEngineView} item can be in one of three \e {lifecycle states}:
+ active, frozen, or discarded. These states, like the sleep states of a CPU,
+ control the resource usage of web views.
+
+ The \e {active} state is the normal, unrestricted state of a web view. All
+ visible web views are always in the active state, as are all web views that
+ have not yet finished loading. Only invisible, idle web views can be
+ transitioned to other lifecycle states.
+
+ The \e {frozen} state is a low CPU usage state. In this state, most HTML
+ task sources are suspended (frozen) and, as a result, most DOM event
+ processing and JavaScript execution will also be suspended. The web view
+ must be invisible in order to be frozen as rendering is not possible in this
+ state.
+
+ The \e {discarded} state is an extreme resource-saving state. In this state,
+ the browsing context of the web view will be discarded and the corresponding
+ renderer subprocess shut down. CPU and memory usage in this state is reduced
+ virtually to zero. On exiting this state the web page will be automatically
+ reloaded. The process of entering and exiting the discarded state is similar
+ to serializing the browsing history of the web view and destroying the view,
+ then creating a new view and restoring its history.
+
+ See also \l {WebEngineView::LifecycleState}. The equivalent in the Widgets
+ API is \l {QWebEnginePage::LifecycleState}.
+
+ \section2 The \c {lifecycleState} and \c {recommendedState} Properties
+
+ The \l {WebEngineView::}{lifecycleState} property of the \l {WebEngineView}
+ type is a read-write property that controls the current lifecycle state of
+ the web view. This property is designed to place as few restrictions as
+ possible on what states can be transitioned to. For example, it is allowed
+ to freeze a web view that is currently playing music in the background,
+ stopping the music. In order to implement a less aggressive resource-saving
+ strategy that avoids interrupting user-visible background activity, the \l
+ {WebEngineView::} {recommendedState} property must be used.
+
+ The \l {WebEngineView::}{recommendedState} property of the \l
+ {WebEngineView} type is a read-only property that calculates a safe limit on
+ the \l {WebEngineView::}{lifecycleState} property, taking into account the
+ current activity of the web view. So, in the example of a web view playing
+ music in the background, the recommended state will be \c {Active} since a
+ more aggressive state would stop the music. If the application wants to
+ avoid interrupting background activity, then it should avoid putting the web
+ view into a more aggressively resource-saving lifecycle state than what's
+ given by \l {WebEngineView::}{recommendedState}.
+
+ See also \l {WebEngineView::lifecycleState} and \l
+ {WebEngineView::recommendedState}. The equivalents in the Widgets API are \l
+ {QWebEnginePage::lifecycleState} and \l {QWebEnginePage::recommendedState}.
+
+ \section2 The Page Lifecycle API
+
+ The \l {WebEngineView::}{lifecycleState} property is connected to the \l
+ {https://wicg.github.io/page-lifecycle/spec.html}{Page Lifecycle API}, a
+ work-in-progress extension to the HTML standard that specifies two new DOM
+ events, \c {freeze} and \c {resume}, and adds a new \c
+ {Document.wasDiscarded} boolean property. The \c {freeze} and \c {resume}
+ events are fired when transitioning from the \c {Active} to the \c {Frozen
+ state}, and vice-versa. The \c {Document.wasDiscarded} property is set to \c
+ {true} when transition from the \c {Discarded} state to the \c {Active}
+ state.
+
+ \section1 Lifecycle States in the Example
+
+ The example implements two ways of changing the lifecycle state: manual and
+ automatic. The manual way uses the \l {WebEngineView::}{lifecycleState}
+ property directly to change the web view lifecycle state, while the
+ automatic way is timer-based and also takes into account the \l
+ {WebEngineView::}{recommendedState}.
+
+ The tab titles in the tab bar are color coded with frozen tabs shown in blue
+ and discarded in red.
+
+ \section2 Manual Lifecycle Control
+
+ \image lifecycle-manual.png
+
+ Manual control is provided by context menus on the tab bar buttons (\c
+ {WebTabButton.qml}). The menu has three radio buttons, one for each
+ lifecycle state, with the current state checked. Some buttons may be
+ disabled, either because they represent illegal state transitions (for
+ example, a \c {Discarded} view cannot directly transition to the \c {Frozen}
+ state), or because other preconditions are not fulfilled (for example, a
+ visible view can only be in the \c {Active} state).
+
+ \section2 Automatic Lifecycle Control
+
+ \image lifecycle-automatic.png
+
+ Automatic control is implemented with a \l {Timer} in the \c {WebTab}
+ component (\c {WebTab.qml}). The timer is started whenever the \l
+ {WebEngineView::}{lifecycleState} of the web view does not match it's \l
+ {WebEngineView::}{recommendedState}. Once the timer fires, the view's
+ lifecycle state is set to the recommended state.
+
+ The time delay is used to avoid changing the lifecycle state too quickly
+ when the user is switching between tabs. The freezing and discarding delays
+ can be changed in the settings drawer accessed through the "⋮" button on the
+ tool bar.
+
+ This is a rather simple algorithm for automatic lifecycle control, however
+ more sophisticated algorithms could also be conceived and implemented on the
+ basis of the \l {WebEngineView::}{lifecycleState} property. For example, the
+ Chromium browser experimentally uses a pretrained deep neural network to
+ predict the next tab activation time by the user, essentially ranking tabs
+ based on how interesting they are to the user. Implementing such an
+ algorithm is left as an exercise to the reader for now.
+
+*/
diff --git a/examples/webengine/lifecycle/lifecycle.pro b/examples/webengine/lifecycle/lifecycle.pro
new file mode 100644
index 000000000..74fbf23c1
--- /dev/null
+++ b/examples/webengine/lifecycle/lifecycle.pro
@@ -0,0 +1,10 @@
+TEMPLATE = app
+
+QT += quickcontrols2 webengine
+
+SOURCES += main.cpp
+
+RESOURCES += resources.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/webengine/lifecycle
+INSTALLS += target
diff --git a/examples/webengine/lifecycle/main.cpp b/examples/webengine/lifecycle/main.cpp
new file mode 100644
index 000000000..83907cbaf
--- /dev/null
+++ b/examples/webengine/lifecycle/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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$
+**
+****************************************************************************/
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QQmlContext>
+#include <QQuickStyle>
+#include <qtwebengineglobal.h>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setOrganizationName("QtExamples");
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QGuiApplication app(argc, argv);
+ QtWebEngine::initialize();
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/WebBrowser.qml")));
+ return app.exec();
+}
diff --git a/examples/webengine/lifecycle/qtquickcontrols2.conf b/examples/webengine/lifecycle/qtquickcontrols2.conf
new file mode 100644
index 000000000..68c77cec5
--- /dev/null
+++ b/examples/webengine/lifecycle/qtquickcontrols2.conf
@@ -0,0 +1,6 @@
+[Controls]
+Style=Material
+
+[Material]
+Theme=Dark
+Variant=Dense
diff --git a/examples/webengine/lifecycle/resources.qrc b/examples/webengine/lifecycle/resources.qrc
new file mode 100644
index 000000000..41e5092ce
--- /dev/null
+++ b/examples/webengine/lifecycle/resources.qrc
@@ -0,0 +1,11 @@
+<RCC>
+ <qresource prefix="/">
+ <file>WebBrowser.qml</file>
+ <file>WebTab.qml</file>
+ <file>WebTabBar.qml</file>
+ <file>WebTabButton.qml</file>
+ <file>WebTabStack.qml</file>
+ <file>WebToolButton.qml</file>
+ <file>qtquickcontrols2.conf</file>
+ </qresource>
+</RCC>
diff --git a/examples/webengine/minimal/main.cpp b/examples/webengine/minimal/main.cpp
index 9db6ea6aa..8bcd0e0e9 100644
--- a/examples/webengine/minimal/main.cpp
+++ b/examples/webengine/minimal/main.cpp
@@ -56,6 +56,7 @@ int main(int argc, char *argv[])
{
QCoreApplication::setOrganizationName("QtExamples");
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QGuiApplication app(argc, argv);
QtWebEngine::initialize();
diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
index 3bc571546..df4bbdb4a 100644
--- a/examples/webengine/quicknanobrowser/ApplicationRoot.qml
+++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
@@ -49,7 +49,7 @@
****************************************************************************/
import QtQuick 2.1
-import QtWebEngine 1.9
+import QtWebEngine 1.10
QtObject {
id: root
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index d095703fb..39a13df59 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -57,7 +57,7 @@ import QtQuick.Controls.Styles 1.0
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.0
import QtQuick.Window 2.1
-import QtWebEngine 1.9
+import QtWebEngine 1.11
ApplicationWindow {
id: browserWindow
@@ -73,6 +73,10 @@ ApplicationWindow {
// Make sure the Qt.WindowFullscreenButtonHint is set on OS X.
Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint
+ onCurrentWebViewChanged: {
+ findBar.reset();
+ }
+
// Create a styleItem to determine the platform.
// When using style "mac", ToolButtons are not supposed to accept focus.
QQCPrivate.StyleItem { id: styleItem }
@@ -136,6 +140,9 @@ ApplicationWindow {
fullScreenNotification.hide();
currentWebView.triggerWebAction(WebEngineView.ExitFullScreen);
}
+
+ if (findBar.visible)
+ findBar.visible = false;
}
}
Action {
@@ -187,6 +194,21 @@ ApplicationWindow {
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()
+ }
toolBar: ToolBar {
id: navigationBar
@@ -553,6 +575,19 @@ ApplicationWindow {
selection.certificates[0].select();
}
+ onFindTextFinished: function(result) {
+ if (!findBar.visible)
+ findBar.visible = true;
+
+ findBar.numberOfMatches = result.numberOfMatches;
+ findBar.activeMatchOrdinal = result.activeMatchOrdinal;
+ }
+
+ onLoadingChanged: function(loadRequest) {
+ if (loadRequest.status == WebEngineView.LoadStartedStatus)
+ findBar.reset();
+ }
+
Timer {
id: reloadTimer
interval: 0
@@ -625,6 +660,28 @@ ApplicationWindow {
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"
diff --git a/examples/webengine/quicknanobrowser/DownloadView.qml b/examples/webengine/quicknanobrowser/DownloadView.qml
index f6ebeab4a..e26c770bc 100644
--- a/examples/webengine/quicknanobrowser/DownloadView.qml
+++ b/examples/webengine/quicknanobrowser/DownloadView.qml
@@ -101,7 +101,7 @@ Rectangle {
}
Label {
id: label
- text: path
+ text: downloadDirectory + "/" + downloadFileName
anchors {
verticalCenter: cancelButton.verticalCenter
left: parent.left
diff --git a/examples/webengine/quicknanobrowser/FindBar.qml b/examples/webengine/quicknanobrowser/FindBar.qml
new file mode 100644
index 000000000..2d673592a
--- /dev/null
+++ b/examples/webengine/quicknanobrowser/FindBar.qml
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** 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 2.5
+import QtQuick.Controls 1.4
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Layouts 1.0
+
+Rectangle {
+ id: root
+
+ property int numberOfMatches: 0
+ property int activeMatchOrdinal: 0
+ property alias text: findTextField.text
+
+ function reset() {
+ numberOfMatches = 0;
+ activeMatchOrdinal = 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
+
+ style: TextFieldStyle {
+ background: Rectangle {
+ color: "transparent"
+ }
+ }
+
+ onAccepted: root.findNext()
+ onTextChanged: root.findNext()
+ onActiveFocusChanged: activeFocus ? selectAll() : deselect()
+ }
+ }
+
+ Label {
+ text: activeMatchOrdinal + "/" + 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/webengine/quicknanobrowser/quicknanobrowser.pro b/examples/webengine/quicknanobrowser/quicknanobrowser.pro
index 5a27f5fd4..922cf79e2 100644
--- a/examples/webengine/quicknanobrowser/quicknanobrowser.pro
+++ b/examples/webengine/quicknanobrowser/quicknanobrowser.pro
@@ -10,6 +10,7 @@ OTHER_FILES += ApplicationRoot.qml \
BrowserDialog.qml \
BrowserWindow.qml \
DownloadView.qml \
+ FindBar.qml \
FullScreenNotification.qml
RESOURCES += resources.qrc
diff --git a/examples/webengine/quicknanobrowser/resources.qrc b/examples/webengine/quicknanobrowser/resources.qrc
index c6270897d..50ea05f5e 100644
--- a/examples/webengine/quicknanobrowser/resources.qrc
+++ b/examples/webengine/quicknanobrowser/resources.qrc
@@ -4,6 +4,7 @@
<file>BrowserDialog.qml</file>
<file>BrowserWindow.qml</file>
<file>DownloadView.qml</file>
+ <file>FindBar.qml</file>
<file>FullScreenNotification.qml</file>
</qresource>
<qresource prefix="icons">
diff --git a/examples/webengine/webengine.pro b/examples/webengine/webengine.pro
index 5ad620390..058868395 100644
--- a/examples/webengine/webengine.pro
+++ b/examples/webengine/webengine.pro
@@ -8,5 +8,6 @@ SUBDIRS += \
qtHaveModule(quickcontrols2) {
SUBDIRS += \
+ lifecycle \
recipebrowser
}
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
index 5d00cd19a..7b167ded7 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.cpp
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
@@ -66,6 +66,7 @@
#include <QStatusBar>
#include <QToolBar>
#include <QVBoxLayout>
+#include <QWebEngineFindTextResult>
#include <QWebEngineProfile>
BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools)
@@ -99,7 +100,7 @@ BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool
QWidget *centralWidget = new QWidget(this);
QVBoxLayout *layout = new QVBoxLayout;
layout->setSpacing(0);
- layout->setMargin(0);
+ layout->setContentsMargins(0, 0, 0, 0);
if (!forDevTools) {
addToolBarBreak();
@@ -129,6 +130,7 @@ BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool
connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() {
m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text()));
});
+ connect(m_tabWidget, &TabWidget::findTextFinished, this, &BrowserWindow::handleFindTextFinished);
QAction *focusUrlLineEditAction = new QAction(this);
addAction(focusUrlLineEditAction);
@@ -460,10 +462,7 @@ void BrowserWindow::handleFindActionTriggered()
m_lastSearch, &ok);
if (ok && !search.isEmpty()) {
m_lastSearch = search;
- currentTab()->findText(m_lastSearch, 0, [this](bool found) {
- if (!found)
- statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
- });
+ currentTab()->findText(m_lastSearch);
}
}
@@ -526,3 +525,14 @@ void BrowserWindow::handleDevToolsRequested(QWebEnginePage *source)
source->setDevToolsPage(m_browser->createDevToolsWindow()->currentTab()->page());
source->triggerAction(QWebEnginePage::InspectElement);
}
+
+void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &result)
+{
+ if (result.numberOfMatches() == 0) {
+ statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
+ } else {
+ statusBar()->showMessage(tr("\"%1\" found: %2/%3").arg(m_lastSearch,
+ QString::number(result.activeMatchOrdinal()),
+ QString::number(result.numberOfMatches())));
+ }
+}
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.h b/examples/webenginewidgets/simplebrowser/browserwindow.h
index 8f328b751..11a655469 100644
--- a/examples/webenginewidgets/simplebrowser/browserwindow.h
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.h
@@ -88,6 +88,7 @@ private slots:
void handleWebViewTitleChanged(const QString &title);
void handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
void handleDevToolsRequested(QWebEnginePage *source);
+ void handleFindTextFinished(const QWebEngineFindTextResult &result);
private:
QMenu *createFileMenu(TabWidget *tabWidget);
diff --git a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
index e0a511475..b6f9e9c13 100644
--- a/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/downloadmanagerwidget.cpp
@@ -55,6 +55,7 @@
#include "downloadwidget.h"
#include <QFileDialog>
+#include <QDir>
#include <QWebEngineDownloadItem>
DownloadManagerWidget::DownloadManagerWidget(QWidget *parent)
@@ -68,11 +69,12 @@ void DownloadManagerWidget::downloadRequested(QWebEngineDownloadItem *download)
{
Q_ASSERT(download && download->state() == QWebEngineDownloadItem::DownloadRequested);
- QString path = QFileDialog::getSaveFileName(this, tr("Save as"), download->path());
+ QString path = QFileDialog::getSaveFileName(this, tr("Save as"), QDir(download->downloadDirectory()).filePath(download->downloadFileName()));
if (path.isEmpty())
return;
- download->setPath(path);
+ download->setDownloadDirectory(QFileInfo(path).path());
+ download->setDownloadFileName(QFileInfo(path).fileName());
download->accept();
add(new DownloadWidget(download));
diff --git a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
index 1d599a19d..ddddc5e5d 100644
--- a/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/downloadwidget.cpp
@@ -57,10 +57,11 @@
DownloadWidget::DownloadWidget(QWebEngineDownloadItem *download, QWidget *parent)
: QFrame(parent)
, m_download(download)
- , m_timeAdded(QTime::currentTime())
+ , m_timeAdded()
{
+ m_timeAdded.start();
setupUi(this);
- m_dstName->setText(QFileInfo(m_download->path()).fileName());
+ m_dstName->setText(m_download->downloadFileName());
m_srcUrl->setText(m_download->url().toDisplayString());
connect(m_cancelButton, &QPushButton::clicked,
diff --git a/examples/webenginewidgets/simplebrowser/downloadwidget.h b/examples/webenginewidgets/simplebrowser/downloadwidget.h
index c08b298bc..c20676aa6 100644
--- a/examples/webenginewidgets/simplebrowser/downloadwidget.h
+++ b/examples/webenginewidgets/simplebrowser/downloadwidget.h
@@ -54,7 +54,7 @@
#include "ui_downloadwidget.h"
#include <QFrame>
-#include <QTime>
+#include <QElapsedTimer>
QT_BEGIN_NAMESPACE
class QWebEngineDownloadItem;
@@ -80,7 +80,7 @@ private:
QString withUnit(qreal bytes);
QWebEngineDownloadItem *m_download;
- QTime m_timeAdded;
+ QElapsedTimer m_timeAdded;
};
#endif // DOWNLOADWIDGET_H
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
index 369bebfd9..3b6d84ebe 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.cpp
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -200,6 +200,10 @@ void TabWidget::setupView(WebView *webView)
closeTab(index);
});
connect(webView, &WebView::devToolsRequested, this, &TabWidget::devToolsRequested);
+ connect(webPage, &QWebEnginePage::findTextFinished, [this, webView](const QWebEngineFindTextResult &result) {
+ if (currentIndex() == indexOf(webView))
+ emit findTextFinished(result);
+ });
}
WebView *TabWidget::createTab()
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.h b/examples/webenginewidgets/simplebrowser/tabwidget.h
index bf83781df..fba61d44f 100644
--- a/examples/webenginewidgets/simplebrowser/tabwidget.h
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.h
@@ -78,6 +78,7 @@ signals:
void favIconChanged(const QIcon &icon);
void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
void devToolsRequested(QWebEnginePage *source);
+ void findTextFinished(const QWebEngineFindTextResult &result);
public slots:
// current tab/page slots
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
index 99849c77d..2e49f651f 100644
--- a/examples/webenginewidgets/simplebrowser/webpage.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -57,6 +57,7 @@
#include <QAuthenticator>
#include <QMessageBox>
#include <QStyle>
+#include <QTimer>
#include <QWebEngineCertificateError>
WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
@@ -74,22 +75,33 @@ WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
bool WebPage::certificateError(const QWebEngineCertificateError &error)
{
QWidget *mainWindow = view()->window();
- if (error.isOverridable()) {
- QDialog dialog(mainWindow);
- dialog.setModal(true);
- dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
- Ui::CertificateErrorDialog certificateDialog;
- certificateDialog.setupUi(&dialog);
- certificateDialog.m_iconLabel->setText(QString());
- QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, mainWindow));
- certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
- certificateDialog.m_errorLabel->setText(error.errorDescription());
- dialog.setWindowTitle(tr("Certificate Error"));
- return dialog.exec() == QDialog::Accepted;
- }
- QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription());
- return false;
+ QWebEngineCertificateError deferredError = error;
+ deferredError.defer();
+
+ QTimer::singleShot(0, mainWindow, [mainWindow, error = std::move(deferredError)] () mutable {
+ if (!error.deferred()) {
+ QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription());
+ } else {
+ QDialog dialog(mainWindow);
+ dialog.setModal(true);
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ Ui::CertificateErrorDialog certificateDialog;
+ certificateDialog.setupUi(&dialog);
+ certificateDialog.m_iconLabel->setText(QString());
+ QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, mainWindow));
+ certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
+ certificateDialog.m_errorLabel->setText(error.errorDescription());
+ dialog.setWindowTitle(tr("Certificate Error"));
+
+ if (dialog.exec() == QDialog::Accepted)
+ error.ignoreCertificateError();
+ else
+ error.rejectCertificate();
+ }
+ });
+ return true;
}
void WebPage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth)
diff --git a/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp b/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp
index 19e3b0124..566723e1f 100644
--- a/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp
+++ b/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp
@@ -66,7 +66,7 @@ WebPopupWindow::WebPopupWindow(QWebEngineProfile *profile)
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QVBoxLayout *layout = new QVBoxLayout;
- layout->setMargin(0);
+ layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout);
layout->addWidget(m_urlLineEdit);
layout->addWidget(m_view);