[Qt] [WK2] Expose onNavigationRequested signal instead of expecting a slot be defined...
authorcaio.oliveira@openbossa.org <caio.oliveira@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Nov 2011 16:52:54 +0000 (16:52 +0000)
committercaio.oliveira@openbossa.org <caio.oliveira@openbossa.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 23 Nov 2011 16:52:54 +0000 (16:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=72976

Reviewed by Tor Arne Vestbø.

Expecting slots/methods to be implemented in QML isn't very idiomatic in
comparison with the alternative of having a signal. So we now use a signal
for handling navigation requests, and expose a 'request' object with relevant
metadata. There's also a settable property 'action' used to indicate whether
the navigation should be ignored or trigger a download.

The pattern signal with an object parameter that can keep the reply is common in QML,
and used for example for mouse signals.

* UIProcess/API/qt/qquickwebview.cpp:
* UIProcess/API/qt/qquickwebview_p.h:
* UIProcess/API/qt/qquickwebview_p_p.h:
* UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationRequested.qml: Renamed from Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationPolicyForUrl.qml.
* UIProcess/API/qt/tests/qmltests/qmltests.pro:
* UIProcess/qt/QtWebPagePolicyClient.cpp:
(NavigationRequest::NavigationRequest):
(NavigationRequest::url):
(NavigationRequest::button):
(NavigationRequest::modifiers):
(NavigationRequest::action):
(NavigationRequest::setAction):
(QtWebPagePolicyClient::decidePolicyForNavigationAction):
* UIProcess/qt/QtWebPagePolicyClient.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@101086 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/UIProcess/API/qt/qquickwebview.cpp
Source/WebKit2/UIProcess/API/qt/qquickwebview_p.h
Source/WebKit2/UIProcess/API/qt/qquickwebview_p_p.h
Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationRequested.qml [moved from Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationPolicyForUrl.qml with 80% similarity]
Source/WebKit2/UIProcess/API/qt/tests/qmltests/qmltests.pro
Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.cpp
Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.h

index 250802197651326e82be303a457c58354c96fd7c..dac0611f82e00dd8215255449db635ee0e4d4131 100644 (file)
@@ -1,3 +1,34 @@
+2011-11-22  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
+
+        [Qt] [WK2] Expose onNavigationRequested signal instead of expecting a slot be defined from QML
+        https://bugs.webkit.org/show_bug.cgi?id=72976
+
+        Reviewed by Tor Arne Vestbø.
+
+        Expecting slots/methods to be implemented in QML isn't very idiomatic in
+        comparison with the alternative of having a signal. So we now use a signal
+        for handling navigation requests, and expose a 'request' object with relevant
+        metadata. There's also a settable property 'action' used to indicate whether
+        the navigation should be ignored or trigger a download.
+
+        The pattern signal with an object parameter that can keep the reply is common in QML,
+        and used for example for mouse signals.
+
+        * UIProcess/API/qt/qquickwebview.cpp:
+        * UIProcess/API/qt/qquickwebview_p.h:
+        * UIProcess/API/qt/qquickwebview_p_p.h:
+        * UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationRequested.qml: Renamed from Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationPolicyForUrl.qml.
+        * UIProcess/API/qt/tests/qmltests/qmltests.pro:
+        * UIProcess/qt/QtWebPagePolicyClient.cpp:
+        (NavigationRequest::NavigationRequest):
+        (NavigationRequest::url):
+        (NavigationRequest::button):
+        (NavigationRequest::modifiers):
+        (NavigationRequest::action):
+        (NavigationRequest::setAction):
+        (QtWebPagePolicyClient::decidePolicyForNavigationAction):
+        * UIProcess/qt/QtWebPagePolicyClient.h:
+
 2011-11-22  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
 
         [Qt] [WK2] Move PagePolicyClient related code to QtWebPagePolicyClient
 2011-11-22  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
 
         [Qt] [WK2] Move PagePolicyClient related code to QtWebPagePolicyClient
index 513e98e48be1ebc776ff0755c04fa2449afa7612..ebf84176087519020229af6fb98c71823616c808 100644 (file)
@@ -344,46 +344,17 @@ void QQuickWebViewPrivate::setViewInAttachedProperties(QObject* object)
     attached->setView(q);
 }
 
     attached->setView(q);
 }
 
-static QtWebPagePolicyClient::PolicyAction toPolicyAction(QQuickWebView::NavigationPolicy policy)
-{
-    switch (policy) {
-    case QQuickWebView::UsePolicy:
-        return QtWebPagePolicyClient::Use;
-    case QQuickWebView::DownloadPolicy:
-        return QtWebPagePolicyClient::Download;
-    case QQuickWebView::IgnorePolicy:
-        return QtWebPagePolicyClient::Ignore;
-    }
-    ASSERT_NOT_REACHED();
-    return QtWebPagePolicyClient::Ignore;
-}
-
-static bool hasMetaMethod(QObject* object, const char* methodName)
-{
-    int methodIndex = object->metaObject()->indexOfMethod(QMetaObject::normalizedSignature(methodName));
-    return methodIndex >= 0 && methodIndex < object->metaObject()->methodCount();
-}
-
 /*!
 /*!
-    \qmlmethod NavigationPolicy DesktopWebView::navigationPolicyForUrl(url, button, modifiers)
+    \qmlsignal WebView::onNavigationRequested(request)
 
 
-    This method should be implemented by the user of DesktopWebView element.
+    This signal is emitted for every navigation request. The request object contains url, button and modifiers properties
+    describing the navigation action, e.g. "a middle click with shift key pressed to 'http://qt-project.org'".
 
 
-    It will be called to decide the policy for a navigation: whether the WebView should ignore the navigation,
-    continue it or start a download. The return value must be one of the policies in the NavigationPolicy enumeration.
-*/
-QtWebPagePolicyClient::PolicyAction QQuickWebViewPrivate::navigationPolicyForURL(const QUrl& url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
-{
-    Q_Q(QQuickWebView);
-    // We need to check this first because invokeMethod() warns if the method doesn't exist for the object.
-    if (!hasMetaMethod(q, "navigationPolicyForUrl(QVariant,QVariant,QVariant)"))
-        return QtWebPagePolicyClient::Use;
+    The navigation will be accepted by default. To change that, one can set the action property to WebView.IgnoreRequest to reject
+    the request or WebView.DownloadRequest to trigger a download instead of navigating to the url.
 
 
-    QVariant ret;
-    if (QMetaObject::invokeMethod(q, "navigationPolicyForUrl", Q_RETURN_ARG(QVariant, ret), Q_ARG(QVariant, url), Q_ARG(QVariant, button), Q_ARG(QVariant, QVariant(modifiers))))
-        return toPolicyAction(static_cast<QQuickWebView::NavigationPolicy>(ret.toInt()));
-    return QtWebPagePolicyClient::Use;
-}
+    The request object cannot be used after the signal handler function ends.
+*/
 
 void QQuickWebViewPrivate::setPageProxy(QtWebPageProxy* pageProxy)
 {
 
 void QQuickWebViewPrivate::setPageProxy(QtWebPageProxy* pageProxy)
 {
index 7be2a89958f1cda280479789efec870a2f97e202..1817d39839280a91875ee907d5878e816987c825 100644 (file)
@@ -56,13 +56,14 @@ class QWEBKIT_EXPORT QQuickWebView : public QQuickItem {
     Q_PROPERTY(bool canReload READ canReload NOTIFY navigationStateChanged FINAL)
     Q_PROPERTY(QWebPreferences* preferences READ preferences CONSTANT FINAL)
     Q_PROPERTY(QQuickWebPage* page READ page CONSTANT FINAL)
     Q_PROPERTY(bool canReload READ canReload NOTIFY navigationStateChanged FINAL)
     Q_PROPERTY(QWebPreferences* preferences READ preferences CONSTANT FINAL)
     Q_PROPERTY(QQuickWebPage* page READ page CONSTANT FINAL)
-    Q_ENUMS(NavigationPolicy)
+    Q_ENUMS(NavigationRequestAction)
     Q_ENUMS(ErrorType)
     Q_ENUMS(ErrorType)
+
 public:
 public:
-    enum NavigationPolicy {
-        UsePolicy,
-        DownloadPolicy,
-        IgnorePolicy
+    enum NavigationRequestAction {
+        AcceptRequest,
+        IgnoreRequest,
+        DownloadRequest
     };
 
     enum ErrorType {
     };
 
     enum ErrorType {
@@ -112,6 +113,7 @@ Q_SIGNALS:
     void linkHovered(const QUrl& url, const QString& title);
     void viewModeChanged();
     void navigationStateChanged();
     void linkHovered(const QUrl& url, const QString& title);
     void viewModeChanged();
     void navigationStateChanged();
+    void navigationRequested(QObject* request);
 
 protected:
     virtual void geometryChanged(const QRectF&, const QRectF&);
 
 protected:
     virtual void geometryChanged(const QRectF&, const QRectF&);
index e320b38a8da4ad1d07551833b1a913873a21bf61..fc8c2cadb8532b4bed1e44a12531de6ded929671 100644 (file)
@@ -70,8 +70,6 @@ public:
     void _q_onOpenPanelFinished(int result);
     void _q_onVisibleChanged();
 
     void _q_onOpenPanelFinished(int result);
     void _q_onVisibleChanged();
 
-    QtWebPagePolicyClient::PolicyAction navigationPolicyForURL(const QUrl&, Qt::MouseButton, Qt::KeyboardModifiers);
-
     void chooseFiles(WKOpenPanelResultListenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType);
     void runJavaScriptAlert(const QString&);
     bool runJavaScriptConfirm(const QString&);
     void chooseFiles(WKOpenPanelResultListenerRef, const QStringList& selectedFileNames, QtWebPageUIClient::FileChooserType);
     void runJavaScriptAlert(const QString&);
     bool runJavaScriptConfirm(const QString&);
similarity index 80%
rename from Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationPolicyForUrl.qml
rename to Source/WebKit2/UIProcess/API/qt/tests/qmltests/DesktopBehavior/tst_navigationRequested.qml
index 3c0d086264498eb49bab18dce2b807d9c5fc977d..1c73373674e9995a7b8a223e0ea2c287925f4b5b 100644 (file)
@@ -8,12 +8,11 @@ Item {
         id: webView
         width: 200
         height: 200
         id: webView
         width: 200
         height: 200
-        function navigationPolicyForUrl(url, button, modifiers) {
-            if (button == Qt.MiddleButton && modifiers & Qt.ControlModifier) {
-                otherWebView.load(url)
-                return DesktopWebView.IgnorePolicy
+        onNavigationRequested: {
+            if (request.button == Qt.MiddleButton && request.modifiers & Qt.ControlModifier) {
+                otherWebView.load(request.url)
+                request.action = WebView.IgnoreRequest
             }
             }
-            return DesktopWebView.UsePolicy
         }
     }
 
         }
     }
 
@@ -34,7 +33,7 @@ Item {
     }
 
     TestCase {
     }
 
     TestCase {
-        name: "DesktopWebViewNavigationPolicyForUrl"
+        name: "DesktopWebViewNavigationRequested"
 
         // Delayed windowShown to workaround problems with Qt5 in debug mode.
         when: false
 
         // Delayed windowShown to workaround problems with Qt5 in debug mode.
         when: false
@@ -49,7 +48,6 @@ Item {
             webView.load(Qt.resolvedUrl("../common/test2.html"))
             spy.wait()
             spy.clear()
             webView.load(Qt.resolvedUrl("../common/test2.html"))
             spy.wait()
             spy.clear()
-            compare(spy.count, 0)
             mouseClick(webView, 100, 100, Qt.LeftButton)
             spy.wait()
             compare(spy.count, 1)
             mouseClick(webView, 100, 100, Qt.LeftButton)
             spy.wait()
             compare(spy.count, 1)
index 7535fb81e90cd1450270c86fcd1971dddeb0e20f..71b85493839bb608d4e3586b3f996833c79f709f 100644 (file)
@@ -27,5 +27,5 @@ OTHER_FILES += \
     DesktopBehavior/tst_linkHovered.qml \
     DesktopBehavior/tst_messaging.qml \
     DesktopBehavior/tst_download.qml \
     DesktopBehavior/tst_linkHovered.qml \
     DesktopBehavior/tst_messaging.qml \
     DesktopBehavior/tst_download.qml \
-    DesktopBehavior/tst_navigationPolicyForUrl.qml \
+    DesktopBehavior/tst_navigationRequested.qml \
     DesktopBehavior/tst_loadHtml.qml
     DesktopBehavior/tst_loadHtml.qml
index 2fafdfe3a8f6e088877dbd518bdf106cd2c1619b..0c0ca64ff47aae845b430826aeb35682f9e0846e 100644 (file)
 #include "WKURLQt.h"
 #include "qquickwebview_p.h"
 #include "qquickwebview_p_p.h"
 #include "WKURLQt.h"
 #include "qquickwebview_p.h"
 #include "qquickwebview_p_p.h"
+#include <QtCore/QObject>
 #include <WKFramePolicyListener.h>
 #include <WKURLRequest.h>
 
 #include <WKFramePolicyListener.h>
 #include <WKURLRequest.h>
 
+class NavigationRequest : public QObject {
+    Q_OBJECT
+    Q_PROPERTY(QUrl url READ url CONSTANT FINAL)
+    Q_PROPERTY(int button READ button CONSTANT FINAL)
+    Q_PROPERTY(int modifiers READ modifiers CONSTANT FINAL)
+    Q_PROPERTY(int action READ action WRITE setAction NOTIFY actionChanged FINAL)
+
+public:
+    NavigationRequest(const QUrl& url, Qt::MouseButton button, Qt::KeyboardModifiers modifiers)
+        : m_url(url)
+        , m_button(button)
+        , m_modifiers(modifiers)
+        , m_action(QQuickWebView::AcceptRequest)
+    {
+    }
+
+    QUrl url() const { return m_url; }
+    int button() const { return int(m_button); }
+    int modifiers() const { return int(m_modifiers); }
+
+    int action() const { return int(m_action); }
+    void setAction(int action)
+    {
+        if (m_action == action)
+            return;
+        m_action = action;
+        emit actionChanged();
+    }
+
+Q_SIGNALS:
+    void actionChanged();
+
+private:
+    QUrl m_url;
+    Qt::MouseButton m_button;
+    Qt::KeyboardModifiers m_modifiers;
+    int m_action;
+};
+
 QtWebPagePolicyClient::QtWebPagePolicyClient(WKPageRef pageRef, QQuickWebView* webView)
     : m_webView(webView)
 {
 QtWebPagePolicyClient::QtWebPagePolicyClient(WKPageRef pageRef, QQuickWebView* webView)
     : m_webView(webView)
 {
@@ -39,9 +79,25 @@ QtWebPagePolicyClient::QtWebPagePolicyClient(WKPageRef pageRef, QQuickWebView* w
     WKPageSetPagePolicyClient(pageRef, &policyClient);
 }
 
     WKPageSetPagePolicyClient(pageRef, &policyClient);
 }
 
-QtWebPagePolicyClient::PolicyAction QtWebPagePolicyClient::decidePolicyForNavigationAction(const QUrl& url, Qt::MouseButton mouseButton, Qt::KeyboardModifiers keyboardModifiers)
+void QtWebPagePolicyClient::decidePolicyForNavigationAction(const QUrl& url, Qt::MouseButton mouseButton, Qt::KeyboardModifiers keyboardModifiers, WKFramePolicyListenerRef listener)
 {
 {
-    return m_webView->d_func()->navigationPolicyForURL(url, mouseButton, keyboardModifiers);
+    // NOTE: even though the C API (and the WebKit2 IPC) supports an asynchronous answer, this is not currently working.
+    // We are expected to call the listener immediately. See the patch for https://bugs.webkit.org/show_bug.cgi?id=53785.
+    NavigationRequest navigationRequest(url, mouseButton, keyboardModifiers);
+    emit m_webView->navigationRequested(&navigationRequest);
+
+    switch (QQuickWebView::NavigationRequestAction(navigationRequest.action())) {
+    case QQuickWebView::IgnoreRequest:
+        WKFramePolicyListenerIgnore(listener);
+        return;
+    case QQuickWebView::DownloadRequest:
+        WKFramePolicyListenerDownload(listener);
+        return;
+    case QQuickWebView::AcceptRequest:
+        WKFramePolicyListenerUse(listener);
+        return;
+    }
+    ASSERT_NOT_REACHED();
 }
 
 static inline QtWebPagePolicyClient* toQtWebPagePolicyClient(const void* clientInfo)
 }
 
 static inline QtWebPagePolicyClient* toQtWebPagePolicyClient(const void* clientInfo)
@@ -85,20 +141,7 @@ void QtWebPagePolicyClient::decidePolicyForNavigationAction(WKPageRef, WKFrameRe
     WKURLRef requestURL = WKURLRequestCopyURL(request);
     QUrl qUrl = WKURLCopyQUrl(requestURL);
     WKRelease(requestURL);
     WKURLRef requestURL = WKURLRequestCopyURL(request);
     QUrl qUrl = WKURLCopyQUrl(requestURL);
     WKRelease(requestURL);
-
-    PolicyAction action = toQtWebPagePolicyClient(clientInfo)->decidePolicyForNavigationAction(qUrl, toQtMouseButton(mouseButton), toQtKeyboardModifiers(modifiers));
-    switch (action) {
-    case Use:
-        WKFramePolicyListenerUse(listener);
-        return;
-    case Download:
-        WKFramePolicyListenerDownload(listener);
-        return;
-    case Ignore:
-        WKFramePolicyListenerIgnore(listener);
-        return;
-    }
-    ASSERT_NOT_REACHED();
+    toQtWebPagePolicyClient(clientInfo)->decidePolicyForNavigationAction(qUrl, toQtMouseButton(mouseButton), toQtKeyboardModifiers(modifiers), listener);
 }
 
 void QtWebPagePolicyClient::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void*)
 }
 
 void QtWebPagePolicyClient::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void*)
@@ -128,3 +171,4 @@ void QtWebPagePolicyClient::decidePolicyForResponse(WKPageRef page, WKFrameRef f
     WKFramePolicyListenerUse(listener);
 }
 
     WKFramePolicyListenerUse(listener);
 }
 
+#include "QtWebPagePolicyClient.moc"
index e411bf6f38299fdf0588fc4c546c7a9f3923b812..936a847b2937d2c24f5ee90f01f706ddc0a3f0a2 100644 (file)
@@ -30,14 +30,8 @@ class QtWebPagePolicyClient {
 public:
     QtWebPagePolicyClient(WKPageRef, QQuickWebView*);
 
 public:
     QtWebPagePolicyClient(WKPageRef, QQuickWebView*);
 
-    enum PolicyAction {
-        Use,
-        Download,
-        Ignore
-    };
-
 private:
 private:
-    PolicyAction decidePolicyForNavigationAction(const QUrl&, Qt::MouseButton, Qt::KeyboardModifiers);
+    void decidePolicyForNavigationAction(const QUrl&, Qt::MouseButton, Qt::KeyboardModifiers, WKFramePolicyListenerRef);
 
     // WKPagePolicyClient callbacks.
     static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef userData, const void* clientInfo);
 
     // WKPagePolicyClient callbacks.
     static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef userData, const void* clientInfo);