summaryrefslogtreecommitdiffstats
path: root/examples/webenginewidgets/notifications
diff options
context:
space:
mode:
Diffstat (limited to 'examples/webenginewidgets/notifications')
-rw-r--r--examples/webenginewidgets/notifications/CMakeLists.txt52
-rw-r--r--examples/webenginewidgets/notifications/data/data.qrc6
-rw-r--r--examples/webenginewidgets/notifications/data/icon.pngbin0 -> 2252 bytes
-rw-r--r--examples/webenginewidgets/notifications/data/index.html90
-rw-r--r--examples/webenginewidgets/notifications/doc/images/notifications-example.pngbin0 -> 14732 bytes
-rw-r--r--examples/webenginewidgets/notifications/doc/src/notifications.qdoc133
-rw-r--r--examples/webenginewidgets/notifications/main.cpp53
-rw-r--r--examples/webenginewidgets/notifications/notificationpopup.h90
-rw-r--r--examples/webenginewidgets/notifications/notifications.pro10
9 files changed, 434 insertions, 0 deletions
diff --git a/examples/webenginewidgets/notifications/CMakeLists.txt b/examples/webenginewidgets/notifications/CMakeLists.txt
new file mode 100644
index 000000000..8cca0ab31
--- /dev/null
+++ b/examples/webenginewidgets/notifications/CMakeLists.txt
@@ -0,0 +1,52 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(notifications LANGUAGES CXX)
+
+set(CMAKE_AUTOMOC ON)
+
+if(NOT DEFINED INSTALL_EXAMPLESDIR)
+ set(INSTALL_EXAMPLESDIR "examples")
+endif()
+
+set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/webenginewidgets/notifications")
+
+find_package(Qt6 REQUIRED COMPONENTS Core Gui WebEngineWidgets)
+
+qt_add_executable(notifications
+ main.cpp
+ notificationpopup.h
+)
+
+set_target_properties(notifications PROPERTIES
+ WIN32_EXECUTABLE TRUE
+ MACOSX_BUNDLE TRUE
+)
+
+target_link_libraries(notifications PUBLIC
+ Qt::Core
+ Qt::Gui
+ Qt::WebEngineWidgets
+)
+
+# Resources:
+set(data_resource_files
+ "data/icon.png"
+ "data/index.html"
+)
+
+qt_add_resources(notifications "data"
+ PREFIX
+ "/"
+ BASE
+ "data"
+ FILES
+ ${data_resource_files}
+)
+
+install(TARGETS notifications
+ RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}"
+ BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}"
+ LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}"
+)
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
new file mode 100644
index 000000000..4c3870c06
--- /dev/null
+++ b/examples/webenginewidgets/notifications/data/icon.png
Binary files differ
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
new file mode 100644
index 000000000..671cd1703
--- /dev/null
+++ b/examples/webenginewidgets/notifications/doc/images/notifications-example.png
Binary files differ
diff --git a/examples/webenginewidgets/notifications/doc/src/notifications.qdoc b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
new file mode 100644
index 000000000..f4fe1818f
--- /dev/null
+++ b/examples/webenginewidgets/notifications/doc/src/notifications.qdoc
@@ -0,0 +1,133 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \example webenginewidgets/notifications
+ \examplecategory {Web Technologies}
+ \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 contains necessary JavaScript code to trigger this request:
+
+ \quotefromfile webenginewidgets/notifications/data/index.html
+ \skipto Notification.requestPermission
+ \printline requestPermission
+ \skipuntil resetPermission
+ \printuntil /\}\)$/
+
+ Also page contains a button for creating a notification. The following
+ JavaScript constructions are executed on the press event:
+
+ \quotefromfile webenginewidgets/notifications/data/index.html
+ \skipto createNotification()
+ \printuntil new Notification
+ \skipuntil Notification was created
+ \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
+ \skipto /\}/
+ \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
+ \printuntil }
+
+ \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
+ \printline /\}$/
+ \printline /\}$/
+*/
diff --git a/examples/webenginewidgets/notifications/main.cpp b/examples/webenginewidgets/notifications/main.cpp
new file mode 100644
index 000000000..c754aff3f
--- /dev/null
+++ b/examples/webenginewidgets/notifications/main.cpp
@@ -0,0 +1,53 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#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::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..57912f204
--- /dev/null
+++ b/examples/webenginewidgets/notifications/notificationpopup.h
@@ -0,0 +1,90 @@
+// Copyright (C) 2019 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+#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