From 398159d941942886b40105680820f497e5ca90a5 Mon Sep 17 00:00:00 2001
From: Zeno Albisser <zeno.albisser@digia.com>
Date: Mon, 17 Jun 2013 15:57:43 +0200
Subject: [PATCH] Add initial API layer for QtQuick and connect the signals
 accordingly.

---
 examples/qtquick/quickwindow.qml |  5 +--
 lib/qquickwebcontentsview.cpp    | 48 +++++++++++++++++++++++++--
 lib/qquickwebcontentsview.h      | 13 +++++++-
 lib/qwebcontentsview.cpp         |  2 +-
 lib/web_contents_delegate_qt.cpp | 56 ++++++++++++++++++++++----------
 lib/web_contents_delegate_qt.h   | 23 ++++++++++---
 6 files changed, 118 insertions(+), 29 deletions(-)

diff --git a/examples/qtquick/quickwindow.qml b/examples/qtquick/quickwindow.qml
index bd6504d6b..688014b6f 100644
--- a/examples/qtquick/quickwindow.qml
+++ b/examples/qtquick/quickwindow.qml
@@ -8,6 +8,7 @@ ApplicationWindow {
     height: 600
     width: 800
     visible: true
+    title: webContentsView.title
 
     toolBar: ToolBar {
         id: navigationBar
@@ -28,8 +29,8 @@ ApplicationWindow {
             }
             ToolButton {
                 id: reloadButton
-                iconName: "view-refresh"
-                iconSource: ":/icons/view-refresh.png"
+                iconName: webContentsView.loading ? "process-stop" : "view-refresh"
+                iconSource: webContentsView.loading ? ":/icons/process-stop.png" : ":/icons/view-refresh.png"
                 onClicked: webContentsView.reload()
             }
             TextField {
diff --git a/lib/qquickwebcontentsview.cpp b/lib/qquickwebcontentsview.cpp
index dec521183..0b56aa543 100644
--- a/lib/qquickwebcontentsview.cpp
+++ b/lib/qquickwebcontentsview.cpp
@@ -44,6 +44,7 @@
 // Needed to get access to content::GetContentClient()
 #define CONTENT_IMPLEMENTATION
 
+#include "content/public/browser/navigation_entry.h"
 #include "content/public/browser/web_contents.h"
 
 #include "browser_context_qt.h"
@@ -60,9 +61,8 @@ void QQuickWebContentsView::registerType()
     qmlRegisterType<QQuickWebContentsView>("QtWebEngine", 1, 0, "WebContentsView");
 }
 
-class QQuickWebContentsViewPrivate
+struct QQuickWebContentsViewPrivate
 {
-public:
     scoped_refptr<WebEngineContext> context;
     scoped_ptr<WebContentsDelegateQt> webContentsDelegate;
 };
@@ -70,11 +70,18 @@ public:
 QQuickWebContentsView::QQuickWebContentsView()
 {
     d.reset(new QQuickWebContentsViewPrivate);
+
     // This has to be the first thing we do.
     d->context = WebEngineContext::current();
 
     content::BrowserContext* browser_context = static_cast<ContentBrowserClientQt*>(content::GetContentClient()->browser())->browser_context();
-    d->webContentsDelegate.reset(WebContentsDelegateQt::CreateNewWindow(browser_context, NULL, MSG_ROUTING_NONE, gfx::Size()));
+    d->webContentsDelegate.reset(new WebContentsDelegateQt(this, browser_context, NULL, MSG_ROUTING_NONE, gfx::Size()));
+
+    WebContentsDelegateQt* delegate = d->webContentsDelegate.get();
+    connect(delegate, SIGNAL(titleChanged(QString)), this, SIGNAL(titleChanged(QString)));
+    connect(delegate, SIGNAL(urlChanged()), this, SIGNAL(urlChanged()));
+    connect(delegate, SIGNAL(loadingStateChanged()), this, SIGNAL(loadingStateChanged()));
+
     WebContentsViewQt* content_view = static_cast<WebContentsViewQt*>(d->webContentsDelegate->web_contents()->GetView());
     QQuickItem* windowContainer = content_view->windowContainer()->qQuickItem();
     windowContainer->setParentItem(this);
@@ -117,3 +124,38 @@ void QQuickWebContentsView::reload()
     d->webContentsDelegate->web_contents()->GetController().Reload(false);
     d->webContentsDelegate->web_contents()->GetView()->Focus();
 }
+
+void QQuickWebContentsView::stop()
+{
+    content::NavigationController& controller = d->webContentsDelegate->web_contents()->GetController();
+
+    int index = controller.GetPendingEntryIndex();
+    if (index != -1)
+        controller.RemoveEntryAtIndex(index);
+
+    d->webContentsDelegate->web_contents()->GetView()->Focus();
+}
+
+bool QQuickWebContentsView::isLoading() const
+{
+    return d->webContentsDelegate->web_contents()->IsLoading();
+}
+
+QString QQuickWebContentsView::title() const
+{
+    content::NavigationEntry* entry = d->webContentsDelegate->web_contents()->GetController().GetVisibleEntry();
+    if (!entry)
+        return QString();
+    return QString::fromUtf16(entry->GetTitle().data());
+}
+
+bool QQuickWebContentsView::canGoBack() const
+{
+    return d->webContentsDelegate->web_contents()->GetController().CanGoBack();
+}
+
+bool QQuickWebContentsView::canGoForward() const
+{
+    return d->webContentsDelegate->web_contents()->GetController().CanGoForward();
+}
+
diff --git a/lib/qquickwebcontentsview.h b/lib/qquickwebcontentsview.h
index 9e9979b0a..c94d5e488 100644
--- a/lib/qquickwebcontentsview.h
+++ b/lib/qquickwebcontentsview.h
@@ -50,6 +50,11 @@ class QQuickWebContentsViewPrivate;
 class Q_DECL_EXPORT QQuickWebContentsView : public QQuickItem {
     Q_OBJECT
     Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
+    Q_PROPERTY(bool loading READ isLoading NOTIFY loadingStateChanged)
+    Q_PROPERTY(QString title READ title NOTIFY titleChanged)
+    Q_PROPERTY(bool canGoBack READ canGoBack NOTIFY loadingStateChanged)
+    Q_PROPERTY(bool canGoForward READ canGoForward NOTIFY loadingStateChanged)
+
 public:
     static void registerType();
 
@@ -58,15 +63,21 @@ public:
 
     QUrl url() const;
     void setUrl(const QUrl&);
+    bool isLoading() const;
+    QString title() const;
+    bool canGoBack() const;
+    bool canGoForward() const;
 
 public Q_SLOTS:
     void goBack();
     void goForward();
     void reload();
+    void stop();
 
 Q_SIGNALS:
-    void titleChanged();
+    void titleChanged(QString);
     void urlChanged();
+    void loadingStateChanged();
 
 private:
     QScopedPointer<QQuickWebContentsViewPrivate> d;
diff --git a/lib/qwebcontentsview.cpp b/lib/qwebcontentsview.cpp
index 3da4c727e..061d518cd 100644
--- a/lib/qwebcontentsview.cpp
+++ b/lib/qwebcontentsview.cpp
@@ -69,7 +69,7 @@ QWebContentsView::QWebContentsView()
     d->context = WebEngineContext::current();
 
     content::BrowserContext* browser_context = static_cast<ContentBrowserClientQt*>(content::GetContentClient()->browser())->browser_context();
-    d->webContentsDelegate.reset(WebContentsDelegateQt::CreateNewWindow(browser_context, NULL, MSG_ROUTING_NONE, gfx::Size()));
+    d->webContentsDelegate.reset(new WebContentsDelegateQt(this, browser_context, NULL, MSG_ROUTING_NONE, gfx::Size()));
     QVBoxLayout *layout = new QVBoxLayout;
     layout->setContentsMargins(0, 0, 0, 0);
     setLayout(layout);
diff --git a/lib/web_contents_delegate_qt.cpp b/lib/web_contents_delegate_qt.cpp
index 71f3e6d9c..d4aad13a0 100644
--- a/lib/web_contents_delegate_qt.cpp
+++ b/lib/web_contents_delegate_qt.cpp
@@ -41,8 +41,14 @@
 
 #include "web_contents_delegate_qt.h"
 
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_types.h"
 #include "content/public/browser/render_view_host.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/invalidate_type.h"
 #include "content/public/common/renderer_preferences.h"
 
 #include <QGuiApplication>
@@ -51,13 +57,8 @@
 static const int kTestWindowWidth = 800;
 static const int kTestWindowHeight = 600;
 
-WebContentsDelegateQt::WebContentsDelegateQt(content::WebContents* web_contents)
-    : m_webContents(web_contents)
-{
-    m_webContents->SetDelegate(this);
-}
-
-WebContentsDelegateQt* WebContentsDelegateQt::CreateNewWindow(content::BrowserContext* browser_context, content::SiteInstance* site_instance, int routing_id, const gfx::Size& initial_size)
+WebContentsDelegateQt::WebContentsDelegateQt(QObject* webContentsView, content::BrowserContext* browser_context, content::SiteInstance* site_instance, int routing_id, const gfx::Size& initial_size)
+    : m_webContentsView(webContentsView)
 {
     content::WebContents::CreateParams create_params(browser_context, site_instance);
     create_params.routing_id = routing_id;
@@ -65,26 +66,47 @@ WebContentsDelegateQt* WebContentsDelegateQt::CreateNewWindow(content::BrowserCo
         create_params.initial_size = initial_size;
     else
         create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight);
-    content::WebContents::Create(create_params);
-    content::WebContents* web_contents = content::WebContents::Create(create_params);
-    WebContentsDelegateQt* delegate = new WebContentsDelegateQt(web_contents);
 
-    content::RendererPreferences* rendererPrefs = delegate->m_webContents->GetMutableRendererPrefs();
+    m_webContents.reset(content::WebContents::Create(create_params));
+
+    content::RendererPreferences* rendererPrefs = m_webContents->GetMutableRendererPrefs();
     rendererPrefs->use_custom_colors = true;
     // Qt returns a flash time (the whole cycle) in ms, chromium expects just the interval in seconds
     const int qtCursorFlashTime = QGuiApplication::styleHints()->cursorFlashTime();
     rendererPrefs->caret_blink_interval = 0.5 * static_cast<double>(qtCursorFlashTime) / 1000;
-    delegate->m_webContents->GetRenderViewHost()->SyncRendererPrefs();
+    m_webContents->GetRenderViewHost()->SyncRendererPrefs();
 
-    return delegate;
+    m_webContents->SetDelegate(this);
+    m_registrar.Add(this, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED, content::Source<content::WebContents>(m_webContents.get()));
 }
 
-content::WebContents* WebContentsDelegateQt::web_contents()
+void WebContentsDelegateQt::Observe(int type, const content::NotificationSource& source, const content::NotificationDetails& details)
 {
-    return m_webContents.get();
+    if (type == content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
+        std::pair<content::NavigationEntry*, bool>* title = content::Details<std::pair<content::NavigationEntry*, bool> >(details).ptr();
+
+        if (title->first) {
+            string16 text = title->first->GetTitle();
+            QString title = QString::fromUtf16(text.data());
+            Q_EMIT titleChanged(title);
+        }
+    }
 }
 
-void WebContentsDelegateQt::Observe(int, const content::NotificationSource&, const content::NotificationDetails&)
+void WebContentsDelegateQt::NavigationStateChanged(const content::WebContents* source, unsigned changed_flags)
 {
-	// IMPLEMENT THIS!!!!
+    if (changed_flags & content::INVALIDATE_TYPE_URL)
+        Q_EMIT urlChanged();
 }
+
+void WebContentsDelegateQt::LoadingStateChanged(content::WebContents* source)
+{
+    Q_EMIT loadingStateChanged();
+}
+
+content::WebContents* WebContentsDelegateQt::web_contents()
+{
+    return m_webContents.get();
+}
+
+
diff --git a/lib/web_contents_delegate_qt.h b/lib/web_contents_delegate_qt.h
index 6e4a16ff4..80776a2d4 100644
--- a/lib/web_contents_delegate_qt.h
+++ b/lib/web_contents_delegate_qt.h
@@ -43,7 +43,11 @@
 #define WEB_CONTENTS_DELEGATE_QT
 
 #include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
 #include "content/public/browser/web_contents_delegate.h"
+#include "content/public/browser/web_contents.h"
+
+#include <QObject>
 
 
 namespace content {
@@ -51,19 +55,28 @@ namespace content {
     class SiteInstance;
 }
 
-class WebContentsDelegateQt : public content::WebContentsDelegate
+class WebContentsDelegateQt : public QObject
+                            , public content::WebContentsDelegate
                             , public content::NotificationObserver
 {
+    Q_OBJECT
 public:
-    static WebContentsDelegateQt* CreateNewWindow(content::BrowserContext*, content::SiteInstance*, int routing_id, const gfx::Size& initial_size);
+    WebContentsDelegateQt(QObject* webContentsView, content::BrowserContext*, content::SiteInstance*, int routing_id, const gfx::Size& initial_size);
     content::WebContents* web_contents();
 
-    virtual void Observe(int, const content::NotificationSource&, const content::NotificationDetails&);
+    virtual void Observe(int type, const content::NotificationSource&, const content::NotificationDetails&);
+    virtual void NavigationStateChanged(const content::WebContents* source, unsigned changed_flags);
+    virtual void LoadingStateChanged(content::WebContents* source);
 
-private:
-    WebContentsDelegateQt(content::WebContents*);
+Q_SIGNALS:
+    void titleChanged(QString title);
+    void urlChanged();
+    void loadingStateChanged();
 
+private:
     scoped_ptr<content::WebContents> m_webContents;
+    content::NotificationRegistrar m_registrar;
+    QObject* m_webContentsView;
 };
 
 #endif
-- 
GitLab