From 76a990cfa3409214530e77d132cdefd9e96685f9 Mon Sep 17 00:00:00 2001
From: Szabolcs David <davidsz@inf.u-szeged.hu>
Date: Mon, 30 Mar 2015 05:58:20 -0700
Subject: [PATCH] Quick: Share profiles between application windows

The applications should not create new WebEngineProfiles for
each window, because the WebEngineView can not adopt content
from a different profile when the target of the NewViewRequest
is a new window (SHIFT+click) or a dialog.

This also adds a notifier signal to the profile property
in order to avoid "non-NOTIFYable" warnings.

Change-Id: I235789f9bfa1a216f99592204e50266242d0ef1c
Reviewed-by: Andras Becsi <andras.becsi@theqtcompany.com>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@theqtcompany.com>
---
 .../quicknanobrowser/ApplicationRoot.qml      | 25 ++++++++--
 .../quicknanobrowser/BrowserDialog.qml        |  2 +-
 .../quicknanobrowser/BrowserWindow.qml        | 47 ++++++++-----------
 src/webengine/api/qquickwebengineview.cpp     |  3 ++
 src/webengine/api/qquickwebengineview_p.h     |  3 +-
 tests/quicktestbrowser/ApplicationRoot.qml    | 25 ++++++++--
 tests/quicktestbrowser/BrowserDialog.qml      |  2 +-
 tests/quicktestbrowser/BrowserWindow.qml      | 46 ++++++++----------
 8 files changed, 90 insertions(+), 63 deletions(-)

diff --git a/examples/webengine/quicknanobrowser/ApplicationRoot.qml b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
index b16ee0078..b409696be 100644
--- a/examples/webengine/quicknanobrowser/ApplicationRoot.qml
+++ b/examples/webengine/quicknanobrowser/ApplicationRoot.qml
@@ -39,9 +39,19 @@
 ****************************************************************************/
 
 import QtQuick 2.1
+import QtWebEngine 1.1
 
 QtObject {
     id: root
+
+    property QtObject defaultProfile: WebEngineProfile {
+        storageName: "Default"
+    }
+
+    property QtObject otrProfile: WebEngineProfile {
+        offTheRecord: true
+    }
+
     property Component browserWindowComponent: BrowserWindow {
         applicationRoot: root
         onClosing: destroy()
@@ -49,10 +59,19 @@ QtObject {
     property Component browserDialogComponent: BrowserDialog {
         onClosing: destroy()
     }
-    function createWindow() { return browserWindowComponent.createObject(root) }
-    function createDialog() { return browserDialogComponent.createObject(root) }
+    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()
+        var browserWindow = createWindow(defaultProfile)
         browserWindow.currentWebView.url = url
     }
 }
diff --git a/examples/webengine/quicknanobrowser/BrowserDialog.qml b/examples/webengine/quicknanobrowser/BrowserDialog.qml
index 302833083..6202d02f7 100644
--- a/examples/webengine/quicknanobrowser/BrowserDialog.qml
+++ b/examples/webengine/quicknanobrowser/BrowserDialog.qml
@@ -40,7 +40,7 @@
 
 import QtQuick 2.1
 import QtQuick.Window 2.2
-import QtWebEngine 1.0
+import QtWebEngine 1.1
 
 Window {
     property alias currentWebView: webView
diff --git a/examples/webengine/quicknanobrowser/BrowserWindow.qml b/examples/webengine/quicknanobrowser/BrowserWindow.qml
index a047b2be5..c4c0270a4 100644
--- a/examples/webengine/quicknanobrowser/BrowserWindow.qml
+++ b/examples/webengine/quicknanobrowser/BrowserWindow.qml
@@ -84,22 +84,6 @@ ApplicationWindow {
         property alias errorPageEnabled: errorPageEnabled.checked;
     }
 
-    WebEngineProfile {
-        id: defaultProfile
-        storageName: "Default"
-        httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
-        onDownloadRequested: {
-            downloadView.visible = true
-            downloadView.append(download)
-            download.accept()
-        }
-    }
-
-    WebEngineProfile {
-        id: otrProfile
-        offTheRecord: true
-    }
-
     Action {
         shortcut: "Ctrl+D"
         onTriggered: {
@@ -124,7 +108,7 @@ ApplicationWindow {
     Action {
         shortcut: "Ctrl+T"
         onTriggered: {
-            tabs.createEmptyTab()
+            tabs.createEmptyTab(currentWebView.profile)
             tabs.currentIndex = tabs.count - 1
             addressBar.forceActiveFocus();
             addressBar.selectAll();
@@ -249,13 +233,15 @@ ApplicationWindow {
                             id: offTheRecordEnabled
                             text: "Off The Record"
                             checkable: true
-                            checked: false
+                            checked: currentWebView.profile.offTheRecord
+                            onToggled: currentWebView.profile = checked ? otrProfile : defaultProfile;
                         }
                         MenuItem {
                             id: httpDiskCacheEnabled
                             text: "HTTP Disk Cache"
-                            checkable: true
-                            checked: (defaultProfile.httpCacheType == WebEngineProfile.DiskHttpCache)
+                            checkable: !currentWebView.profile.offTheRecord
+                            checked: (currentWebView.profile.httpCacheType == WebEngineProfile.DiskHttpCache)
+                            onToggled: currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache
                         }
                     }
                 }
@@ -282,23 +268,23 @@ ApplicationWindow {
 
     TabView {
         id: tabs
-        function createEmptyTab() {
+        function createEmptyTab(profile) {
             var tab = addTab("", tabComponent)
             // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately.
             tab.active = true
             tab.title = Qt.binding(function() { return tab.item.title })
+            tab.item.profile = profile
             return tab
         }
 
         anchors.fill: parent
-        Component.onCompleted: createEmptyTab()
+        Component.onCompleted: createEmptyTab(defaultProfile)
 
         Component {
             id: tabComponent
             WebEngineView {
                 id: webEngineView
                 focus: true
-                profile: offTheRecordEnabled.checked ? otrProfile : defaultProfile
 
                 onLinkHovered: {
                     if (hoveredUrl == "")
@@ -336,17 +322,17 @@ ApplicationWindow {
                     if (!request.userInitiated)
                         print("Warning: Blocked a popup window.")
                     else if (request.destination == WebEngineView.NewViewInTab) {
-                        var tab = tabs.createEmptyTab()
+                        var tab = tabs.createEmptyTab(currentWebView.profile)
                         tabs.currentIndex = tabs.count - 1
                         request.openIn(tab.item)
                     } else if (request.destination == WebEngineView.NewViewInBackgroundTab) {
-                        var tab = tabs.createEmptyTab()
+                        var tab = tabs.createEmptyTab(currentWebView.profile)
                         request.openIn(tab.item)
                     } else if (request.destination == WebEngineView.NewViewInDialog) {
-                        var dialog = applicationRoot.createDialog()
+                        var dialog = applicationRoot.createDialog(currentWebView.profile)
                         request.openIn(dialog.currentWebView)
                     } else {
-                        var window = applicationRoot.createWindow()
+                        var window = applicationRoot.createWindow(currentWebView.profile)
                         request.openIn(window.currentWebView)
                     }
                 }
@@ -401,6 +387,13 @@ ApplicationWindow {
         visible: false
         anchors.fill: parent
     }
+
+    function onDownloadRequested(download) {
+        downloadView.visible = true
+        downloadView.append(download)
+        download.accept()
+    }
+
     Rectangle {
         id: statusBubble
         color: "oldlace"
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index bc58e2526..8b2adab58 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -724,9 +724,12 @@ QQmlListProperty<QQuickWebEngineScript> QQuickWebEngineView::userScripts()
 
 void QQuickWebEngineViewPrivate::setProfile(QQuickWebEngineProfile *profile)
 {
+    Q_Q(QQuickWebEngineView);
+
     if (profile == m_profile)
         return;
     m_profile = profile;
+    Q_EMIT q->profileChanged();
     m_settings->setParentSettings(profile->settings());
 
     if (adapter && adapter->browserContext() != browserContextAdapter()->browserContext()) {
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 4539ad34b..40299c1c5 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -84,7 +84,7 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
     Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY urlChanged)
     Q_PROPERTY(bool isFullScreen READ isFullScreen NOTIFY isFullScreenChanged REVISION 1)
     Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged REVISION 1)
-    Q_PROPERTY(QQuickWebEngineProfile *profile READ profile WRITE setProfile FINAL REVISION 1)
+    Q_PROPERTY(QQuickWebEngineProfile *profile READ profile WRITE setProfile NOTIFY profileChanged FINAL REVISION 1)
     Q_PROPERTY(QQuickWebEngineSettings *settings READ settings REVISION 1)
     Q_PROPERTY(QQuickWebEngineHistory *navigationHistory READ navigationHistory CONSTANT FINAL REVISION 1)
     Q_PROPERTY(QQmlWebChannel *webChannel READ webChannel WRITE setWebChannel NOTIFY webChannelChanged REVISION 1)
@@ -228,6 +228,7 @@ Q_SIGNALS:
     Q_REVISION(1) void featurePermissionRequested(const QUrl &securityOrigin, Feature feature);
     Q_REVISION(1) void newViewRequested(QQuickWebEngineNewViewRequest *request);
     Q_REVISION(1) void zoomFactorChanged(qreal arg);
+    Q_REVISION(1) void profileChanged();
     Q_REVISION(1) void webChannelChanged();
 
 
diff --git a/tests/quicktestbrowser/ApplicationRoot.qml b/tests/quicktestbrowser/ApplicationRoot.qml
index b16ee0078..71737694d 100644
--- a/tests/quicktestbrowser/ApplicationRoot.qml
+++ b/tests/quicktestbrowser/ApplicationRoot.qml
@@ -39,9 +39,19 @@
 ****************************************************************************/
 
 import QtQuick 2.1
+import QtWebEngine 1.1
 
 QtObject {
     id: root
+
+    property QtObject testProfile: WebEngineProfile {
+        storageName: "Test"
+    }
+
+    property QtObject otrProfile: WebEngineProfile {
+        offTheRecord: true
+    }
+
     property Component browserWindowComponent: BrowserWindow {
         applicationRoot: root
         onClosing: destroy()
@@ -49,10 +59,19 @@ QtObject {
     property Component browserDialogComponent: BrowserDialog {
         onClosing: destroy()
     }
-    function createWindow() { return browserWindowComponent.createObject(root) }
-    function createDialog() { return browserDialogComponent.createObject(root) }
+    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()
+        var browserWindow = createWindow(testProfile)
         browserWindow.currentWebView.url = url
     }
 }
diff --git a/tests/quicktestbrowser/BrowserDialog.qml b/tests/quicktestbrowser/BrowserDialog.qml
index 302833083..6202d02f7 100644
--- a/tests/quicktestbrowser/BrowserDialog.qml
+++ b/tests/quicktestbrowser/BrowserDialog.qml
@@ -40,7 +40,7 @@
 
 import QtQuick 2.1
 import QtQuick.Window 2.2
-import QtWebEngine 1.0
+import QtWebEngine 1.1
 
 Window {
     property alias currentWebView: webView
diff --git a/tests/quicktestbrowser/BrowserWindow.qml b/tests/quicktestbrowser/BrowserWindow.qml
index e173080dd..f93a6ccd1 100644
--- a/tests/quicktestbrowser/BrowserWindow.qml
+++ b/tests/quicktestbrowser/BrowserWindow.qml
@@ -78,22 +78,6 @@ ApplicationWindow {
         property alias errorPageEnabled: errorPageEnabled.checked;
     }
 
-    WebEngineProfile {
-        id: testProfile
-        storageName: "Test"
-        httpCacheType: httpDiskCacheEnabled.checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
-        onDownloadRequested: {
-            downloadView.visible = true
-            downloadView.append(download)
-            download.accept()
-        }
-    }
-
-    WebEngineProfile {
-        id: otrProfile
-        offTheRecord: true
-    }
-
     // Make sure the Qt.WindowFullscreenButtonHint is set on OS X.
     Component.onCompleted: flags = flags | Qt.WindowFullscreenButtonHint
 
@@ -127,7 +111,7 @@ ApplicationWindow {
     Action {
         shortcut: "Ctrl+T"
         onTriggered: {
-            tabs.createEmptyTab()
+            tabs.createEmptyTab(currentWebView.profile)
             tabs.currentIndex = tabs.count - 1
             addressBar.forceActiveFocus();
             addressBar.selectAll();
@@ -264,13 +248,15 @@ ApplicationWindow {
                             id: offTheRecordEnabled
                             text: "Off The Record"
                             checkable: true
-                            checked: false
+                            checked: currentWebView.profile.offTheRecord
+                            onToggled: currentWebView.profile = checked ? otrProfile : testProfile;
                         }
                         MenuItem {
                             id: httpDiskCacheEnabled
                             text: "HTTP Disk Cache"
-                            checkable: true
-                            checked: (testProfile.httpCacheType == WebEngineProfile.DiskHttpCache)
+                            checkable: !currentWebView.profile.offTheRecord
+                            checked: (currentWebView.profile.httpCacheType == WebEngineProfile.DiskHttpCache)
+                            onToggled: currentWebView.profile.httpCacheType = checked ? WebEngineProfile.DiskHttpCache : WebEngineProfile.MemoryHttpCache;
                         }
                     }
                 }
@@ -297,16 +283,17 @@ ApplicationWindow {
 
     TabView {
         id: tabs
-        function createEmptyTab() {
+        function createEmptyTab(profile) {
             var tab = addTab("", tabComponent)
             // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately.
             tab.active = true
             tab.title = Qt.binding(function() { return tab.item.title })
+            tab.item.webView.profile = profile
             return tab
         }
 
         anchors.fill: parent
-        Component.onCompleted: createEmptyTab()
+        Component.onCompleted: createEmptyTab(testProfile)
 
         Component {
             id: tabComponent
@@ -335,7 +322,6 @@ ApplicationWindow {
 
                 WebEngineView {
                     id: webEngineView
-                    profile: offTheRecordEnabled.checked ? otrProfile : testProfile
 
                     anchors {
                         fill: parent
@@ -375,17 +361,17 @@ ApplicationWindow {
                         if (!request.userInitiated)
                             print("Warning: Blocked a popup window.")
                         else if (request.destination == WebEngineView.NewViewInTab) {
-                            var tab = tabs.createEmptyTab()
+                            var tab = tabs.createEmptyTab(currentWebView.profile)
                             tabs.currentIndex = tabs.count - 1
                             request.openIn(tab.item.webView)
                         } else if (request.destination == WebEngineView.NewViewInBackgroundTab) {
-                            var tab = tabs.createEmptyTab()
+                            var tab = tabs.createEmptyTab(currentWebView.profile)
                             request.openIn(tab.item.webView)
                         } else if (request.destination == WebEngineView.NewViewInDialog) {
-                            var dialog = applicationRoot.createDialog()
+                            var dialog = applicationRoot.createDialog(currentWebView.profile)
                             request.openIn(dialog.currentWebView)
                         } else {
-                            var window = applicationRoot.createWindow()
+                            var window = applicationRoot.createWindow(currentWebView.profile)
                             request.openIn(window.currentWebView)
                         }
                     }
@@ -506,6 +492,12 @@ ApplicationWindow {
         anchors.fill: parent
     }
 
+    function onDownloadRequested(download) {
+        downloadView.visible = true
+        downloadView.append(download)
+        download.accept()
+    }
+
     ZoomController {
       id: zoomController
       y: parent.mapFromItem(currentWebView, 0 , 0).y - 4
-- 
GitLab