diff options
author | Kirill Burtsev <kirill.burtsev@qt.io> | 2019-03-19 10:15:07 +0100 |
---|---|---|
committer | Kirill Burtsev <kirill.burtsev@qt.io> | 2019-05-20 13:50:39 +0200 |
commit | 8e8cd9ea03dbdfab4d1707ca751b72dd6ac3c178 (patch) | |
tree | b99e1135cca621c42a5ff8e4e298c48122526e3b /examples | |
parent | 819aa370ec413ba1ea4506d591d4debe87c21831 (diff) |
Web Notifications widgets' API example
Change-Id: If6aba0e9da1ece59c91be03ae2f56513e758f5e5
Reviewed-by: Kai Koehne <kai.koehne@qt.io>
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Diffstat (limited to 'examples')
-rw-r--r-- | examples/webenginewidgets/notifications/data/data.qrc | 6 | ||||
-rw-r--r-- | examples/webenginewidgets/notifications/data/icon.png | bin | 0 -> 2252 bytes | |||
-rw-r--r-- | examples/webenginewidgets/notifications/data/index.html | 90 | ||||
-rw-r--r-- | examples/webenginewidgets/notifications/doc/images/notifications-example.png | bin | 0 -> 14732 bytes | |||
-rw-r--r-- | examples/webenginewidgets/notifications/doc/src/notifications.qdoc | 156 | ||||
-rw-r--r-- | examples/webenginewidgets/notifications/main.cpp | 100 | ||||
-rw-r--r-- | examples/webenginewidgets/notifications/notificationpopup.h | 132 | ||||
-rw-r--r-- | examples/webenginewidgets/notifications/notifications.pro | 10 | ||||
-rw-r--r-- | examples/webenginewidgets/webenginewidgets.pro | 1 |
9 files changed, 495 insertions, 0 deletions
diff --git a/examples/webenginewidgets/notifications/data/data.qrc b/examples/webenginewidgets/notifications/data/data.qrc new file mode 100644 index 000000000..bc252b89c --- /dev/null +++ b/examples/webenginewidgets/notifications/data/data.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>index.html</file> + <file>icon.png</file> + </qresource> +</RCC> diff --git a/examples/webenginewidgets/notifications/data/icon.png b/examples/webenginewidgets/notifications/data/icon.png Binary files differnew file mode 100644 index 000000000..4c3870c06 --- /dev/null +++ b/examples/webenginewidgets/notifications/data/icon.png diff --git a/examples/webenginewidgets/notifications/data/index.html b/examples/webenginewidgets/notifications/data/index.html new file mode 100644 index 000000000..ebb73b573 --- /dev/null +++ b/examples/webenginewidgets/notifications/data/index.html @@ -0,0 +1,90 @@ +<!doctype html> +<html> +<head> +<title>Web Notifications Example</title> +<script> + var notificationsCreated = 0 + + function getPermission() { return document.Notification } + function resetPermission(permission = 'default') { + document.Notification = permission + document.getElementById('state').value = getPermission() + } + + function createNotification() { + let title = 'Notification #' + ++notificationsCreated + let options = { body: 'Visit doc.qt.io for more info!', icon: 'icon.png', } + + let notification = new Notification(title, options) + document.notification = notification + + notification.onerror = function(error) { + document.getElementById('act').value += ' with error' + document.notification = null + } + notification.onshow = function() { + document.getElementById('act').value += ', shown' + document.getElementById('close').style.display = 'inline' + } + notification.onclick = function() { + document.getElementById('act').value += ', clicked' + } + notification.onclose = function() { + if (document.notification && notification == document.notification) { + document.getElementById('act').value += ' and closed' + document.getElementById('close').style.display = 'none' + document.notification = null + } + } + + console.log('...notification created [Title: ' + title + ']') + document.getElementById('act').value = 'Notification was created' + } + + function onMakeNotification() { + if (getPermission() == 'granted') { + createNotification() + } else if (getPermission() == 'denied') { + setTimeout(function() { + if (window.confirm('Notifications are disabled!\n' + + 'Permission needs to be granted by user. Reset?')) + resetPermission() + }, 1) + } else { + Notification.requestPermission().then(function (permission) { + console.info('notifications request: ' + permission) + resetPermission(permission) + if (permission == 'granted') + createNotification() + }) + } + } + + function closeNotification() { if (document.notification) document.notification.close() } + + document.addEventListener('DOMContentLoaded', function() { resetPermission(Notification.permission) }) +</script> +</head> +<body style='text-align:center;'> + <h3>Click the button to send a notification</h3> + + <button onclick='onMakeNotification()'>Notify!</button> + + <p> + <output id='act'></output> + <button id='close' style='display: none;' onclick='closeNotification()'>Close</button> + </p><br> + + <p> + <label for='state'>Permission:</label> + <output id='state'></output> + <button onclick='resetPermission()'>Reset</button> + </p><br> + + <h4>More info can be found on:</h4> + <ul style='list-style-type: none;'> + <li>W3 <a href='https://www.w3.org/TR/notifications'>Web Notifications</a> standard</li> + <li>Documentation for <a href='https://doc.qt.io'>Qt WebEngine</a> module</li> + </ul> +</body> +</html> diff --git a/examples/webenginewidgets/notifications/doc/images/notifications-example.png b/examples/webenginewidgets/notifications/doc/images/notifications-example.png Binary files differnew file mode 100644 index 000000000..671cd1703 --- /dev/null +++ b/examples/webenginewidgets/notifications/doc/images/notifications-example.png diff --git a/examples/webenginewidgets/notifications/doc/src/notifications.qdoc b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc new file mode 100644 index 000000000..2c999e7e1 --- /dev/null +++ b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc @@ -0,0 +1,156 @@ +/**************************************************************************** +** +** 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 webenginewidgets/notifications + \title WebEngine Notifications Example + \ingroup webengine-widgetexamples + \brief Demonstrates how to pass HTML5 web notifications to users. + + \image notifications-example.png + + \e {\WebEngine Notifications} demonstrates how to use the + \l QWebEngineProfile::setNotificationPresenter() method and + \l QWebEngineNotification class to show an HTML5 web + notification to the user. + + \include examples-run.qdocinc + + \section1 HTML Page + + In this example, we create an internal HTML page that is added through + a resource collection file (.qrc). The page displays buttons for requesting + permissions and creating a notification. In addition, it contains JavaScript + logic for triggering these actions. + + \quotefromfile webenginewidgets/notifications/data/index.html + \skipto Notification.requestPermission + \printline requestPermission + \dots + \skipto if + \printuntil createNotification() + \printline /^})$/ + + \quotefromfile webenginewidgets/notifications/data/index.html + \skipto createNotification() + \printuntil Notification + \dots + \printline /^})$/ + + \section1 Main Function + + In the \c main function, we instantiate a QWebEngineView, load our internal + HTML page, and set up the required callbacks for notifications handling. + + \section2 Requesting Feature Permissions + + We then use the \l QWebEnginePage::featurePermissionRequested() call to + request the user's permission to show notifications on their device. + + \quotefromfile webenginewidgets/notifications/main.cpp + \skipto featurePermissionRequested + \printuntil }); + + \section2 Handling New Notifications + + We then construct a \c NotificationPopup that encapsulates + the data of the HTML web notification. We also use the + \l QWebEngineProfile::setNotificationPresenter() call to set + our handler, which we use in conjunction with our \c popup + to handle all new notifications. + + \skipto popup + \printuntil }); + + \section1 Presenting Notifications to Users + + The \c NotificationPopup class in this example is a simple + QWidget-based class that uses multiple QLabel instances + for displaying the notification's title, message, and icon. + + \quotefromfile webenginewidgets/notifications/notificationpopup.h + \skipto class NotificationPopup + \printto public: + + \section2 Presenting Notifications + + Inside the \c present method, we first close and release the previous + notification if we have one and then take ownership of a new notification + by calling the \c std::unique_ptr::swap method on our internal notification + instance. + + \skipto present + \printto m_title + + Then we query the notification instance for a title, a message, + and an icon by calling \l QWebEngineNotification::title(), + \l QWebEngineNotification::message(), \l QWebEngineNotification::icon() + and set up the appropriate labels in our popup. + + \printuntil m_icon + + After that we are ready to display our notification to the user + by calling the \l QWidget::show() method. On this step we also call the + \l QWebEngineNotification::show() method to notify \c JavaScript code + about our \e show event. + + \printuntil notification->show + + Finally, we set up a callback to handle the \e close event from the + \c JavaScript side by connecting to the \l QWebEngineNotification::closed() + signal. We also schedule a timer event to close our active notification + automatically. + + \skipto QWebEngineNotification::closed + \printuntil QTimer + \printline /^\}/ + + \section2 Closing Active Notification + + We execute the \e close step for the currently active notification either by + timeout or by handling the \c JavaScript event. First, we hide the popup + widget itself by calling \l QWidget::hide(). Then, we notify the \c JavaScript + code by calling the \l QWebEngineNotification::close() method. Finally, we + destroy the notification object through the \c std::unique_ptr::reset() method. + + \skipto onClosed + \dots + \skipto hide() + \printuntil reset + + \section2 Implementing User Interaction + + To implement the \e click step for a notification, we handle mouse interaction + through \l QWidget::mouseReleaseEvent(). On this event, the \c JavaScript code + is notified by calling the \l QWebEngineNotification::click() method. + Then we automatically perform the \e close step as a notification is + considered fully handled and no longer needed, and therefore can be destroyed. + + \skipto mouseReleaseEvent + \printuntil onClosed + \printuntil /^\}/ +*/ diff --git a/examples/webenginewidgets/notifications/main.cpp b/examples/webenginewidgets/notifications/main.cpp new file mode 100644 index 000000000..661b82ff5 --- /dev/null +++ b/examples/webenginewidgets/notifications/main.cpp @@ -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$ +** +****************************************************************************/ + +#include "notificationpopup.h" + +#include <QApplication> +#include <QDesktopServices> +#include <QWebEnginePage> +#include <QWebEngineProfile> +#include <QWebEngineView> + +class WebEnginePage : public QWebEnginePage { +public: + WebEnginePage(QWidget *parent) : QWebEnginePage(parent) { } + + bool acceptNavigationRequest(const QUrl &url, NavigationType, bool) override { + if (url.scheme() != "https") + return true; + QDesktopServices::openUrl(url); + return false; + } +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QCoreApplication::setOrganizationName("QtExamples"); + QApplication app(argc, argv); + + QWebEngineView view; + + // set custom page to open all page's links for https scheme in system browser + view.setPage(new WebEnginePage(&view)); + + QObject::connect(view.page(), &QWebEnginePage::featurePermissionRequested, + [&] (const QUrl &origin, QWebEnginePage::Feature feature) { + if (feature != QWebEnginePage::Notifications) + return; + view.page()->setFeaturePermission(origin, feature, QWebEnginePage::PermissionGrantedByUser); + }); + + auto profile = view.page()->profile(); + auto popup = new NotificationPopup(&view); + profile->setNotificationPresenter([&] (std::unique_ptr<QWebEngineNotification> notification) { + popup->present(notification); + }); + + view.resize(640, 480); + view.show(); + view.setUrl(QStringLiteral("qrc:/index.html")); + return app.exec(); +} + diff --git a/examples/webenginewidgets/notifications/notificationpopup.h b/examples/webenginewidgets/notifications/notificationpopup.h new file mode 100644 index 000000000..fcbb003b9 --- /dev/null +++ b/examples/webenginewidgets/notifications/notificationpopup.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#pragma once + +#include <QHBoxLayout> +#include <QLabel> +#include <QMouseEvent> +#include <QPushButton> +#include <QSpacerItem> +#include <QTimer> +#include <QVBoxLayout> +#include <QWebEngineNotification> + +#include <memory> + +class NotificationPopup : public QWidget { + Q_OBJECT + + QLabel m_icon, m_title, m_message; + std::unique_ptr<QWebEngineNotification> notification; + +public: + NotificationPopup(QWidget *parent) : QWidget(parent) { + setWindowFlags(Qt::ToolTip); + auto rootLayout = new QHBoxLayout(this); + + rootLayout->addWidget(&m_icon); + + auto bodyLayout = new QVBoxLayout; + rootLayout->addLayout(bodyLayout); + + auto titleLayout = new QHBoxLayout; + bodyLayout->addLayout(titleLayout); + + titleLayout->addWidget(&m_title); + titleLayout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding)); + + auto close = new QPushButton(tr("Close")); + titleLayout->addWidget(close); + connect(close, &QPushButton::clicked, this, &NotificationPopup::onClosed); + + bodyLayout->addWidget(&m_message); + adjustSize(); + } + + void present(std::unique_ptr<QWebEngineNotification> &newNotification) { + if (notification) { + notification->close(); + notification.reset(); + } + + notification.swap(newNotification); + + m_title.setText("<b>" + notification->title() + "</b>"); + m_message.setText(notification->message()); + m_icon.setPixmap(QPixmap::fromImage(notification->icon()).scaledToHeight(m_icon.height())); + + show(); + notification->show(); + + connect(notification.get(), &QWebEngineNotification::closed, this, &NotificationPopup::onClosed); + QTimer::singleShot(10000, notification.get(), [&] () { onClosed(); }); + + // position our popup in the right corner of its parent widget + move(parentWidget()->mapToGlobal(parentWidget()->rect().bottomRight() - QPoint(width() + 10, height() + 10))); + } + +protected slots: + void onClosed() { + hide(); + notification->close(); + notification.reset(); + } + +protected: + void mouseReleaseEvent(QMouseEvent *event) override { + QWidget::mouseReleaseEvent(event); + if (notification && event->button() == Qt::LeftButton) { + notification->click(); + onClosed(); + } + } +}; + diff --git a/examples/webenginewidgets/notifications/notifications.pro b/examples/webenginewidgets/notifications/notifications.pro new file mode 100644 index 000000000..6e276d405 --- /dev/null +++ b/examples/webenginewidgets/notifications/notifications.pro @@ -0,0 +1,10 @@ +QT += webenginewidgets + +HEADERS = notificationpopup.h + +SOURCES = main.cpp + +RESOURCES = data/data.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/notifications +INSTALLS += target diff --git a/examples/webenginewidgets/webenginewidgets.pro b/examples/webenginewidgets/webenginewidgets.pro index 0d47aac80..deb42a8cd 100644 --- a/examples/webenginewidgets/webenginewidgets.pro +++ b/examples/webenginewidgets/webenginewidgets.pro @@ -7,6 +7,7 @@ SUBDIRS += \ minimal \ contentmanipulation \ cookiebrowser \ + notifications \ simplebrowser \ stylesheetbrowser \ videoplayer \ |