summaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorMichal Klocek <michal.klocek@theqtcompany.com>2016-02-23 15:48:03 +0100
committerKai Koehne <kai.koehne@theqtcompany.com>2016-03-16 07:58:00 +0000
commit0b6a32543f53784789991a4d4e8ad4f98c8446c6 (patch)
tree6c717eaf2114aa07c581d0d67534e6ff6828a877 /examples
parentb3cc469ef024c864be6b6e757e7759736e373fef (diff)
Strip down demobrowser to become simplebrowser
Demobrowser changes: * remove QLocalServer/Socket * remove AutoSaver * remove restoreLastSession * remove general QSettings * remove downloadManager * remove bookmarkManager * remove historyManager * remove searchBar * favor setStyleSheet over overriding paint methods * use lambdas where suitable * use QProgressBar instead of own painted widget * use QToolButton instead of own painted buttons * remove QStackWidget, use single UrlLineEdit per window instead of per tab * split files to keep own classes: webpage and webview * remove tracking windows by QPoiner * remove WebPageActionMapper, TabBar classes * remove QDrag dead code * remove special OS X close app handling * fix encapsulation, clean up application logic Change-Id: I4849b6a2de739dea4f01229abdb90418601a2397 Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com> Reviewed-by: Alexandru Croitor <alexandru.croitor@theqtcompany.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/examples.pro3
-rw-r--r--examples/webenginewidgets/simplebrowser/browser.cpp88
-rw-r--r--examples/webenginewidgets/simplebrowser/browser.h61
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.cpp437
-rw-r--r--examples/webenginewidgets/simplebrowser/browserwindow.h101
-rw-r--r--examples/webenginewidgets/simplebrowser/certificateerrordialog.ui133
-rw-r--r--examples/webenginewidgets/simplebrowser/data/addtab.pngbin0 -> 469 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/closetab.pngbin0 -> 516 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/defaulticon.pngbin0 -> 1473 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/go-next.pngbin0 -> 930 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/go-previous.pngbin0 -> 955 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/process-stop.pngbin0 -> 1272 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/data/simplebrowser.qrc12
-rw-r--r--examples/webenginewidgets/simplebrowser/data/simplebrowser.svg24
-rw-r--r--examples/webenginewidgets/simplebrowser/data/view-refresh.pngbin0 -> 1364 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.pngbin0 -> 10515 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.pngbin0 -> 70625 bytes
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser-model.qmodel938
-rw-r--r--examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc263
-rw-r--r--examples/webenginewidgets/simplebrowser/main.cpp60
-rw-r--r--examples/webenginewidgets/simplebrowser/passworddialog.ui121
-rw-r--r--examples/webenginewidgets/simplebrowser/simplebrowser.pro33
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.cpp277
-rw-r--r--examples/webenginewidgets/simplebrowser/tabwidget.h95
-rw-r--r--examples/webenginewidgets/simplebrowser/urllineedit.cpp95
-rw-r--r--examples/webenginewidgets/simplebrowser/urllineedit.h70
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.cpp132
-rw-r--r--examples/webenginewidgets/simplebrowser/webpage.h61
-rw-r--r--examples/webenginewidgets/simplebrowser/webpopupwindow.cpp95
-rw-r--r--examples/webenginewidgets/simplebrowser/webpopupwindow.h71
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.cpp189
-rw-r--r--examples/webenginewidgets/simplebrowser/webview.h82
32 files changed, 3440 insertions, 1 deletions
diff --git a/examples/examples.pro b/examples/examples.pro
index 342c2c311..0de2ec505 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -12,5 +12,6 @@ qtHaveModule(webenginewidgets) {
webenginewidgets/contentmanipulation \
webenginewidgets/cookiebrowser \
webenginewidgets/demobrowser \
- webenginewidgets/markdowneditor
+ webenginewidgets/markdowneditor \
+ webenginewidgets/simplebrowser \
}
diff --git a/examples/webenginewidgets/simplebrowser/browser.cpp b/examples/webenginewidgets/simplebrowser/browser.cpp
new file mode 100644
index 000000000..78b60b8f8
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/browser.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "browser.h"
+#include "browserwindow.h"
+#include "webview.h"
+#include <QAuthenticator>
+#include <QNetworkProxy>
+#include <QNetworkReply>
+
+Browser::Browser()
+{
+ // QTBUG-47967 , downloading favIcon support is coming in 5.7
+ QObject::connect(&WebView::networkAccessManager(), &QNetworkAccessManager::authenticationRequired,
+ [](QNetworkReply *, QAuthenticator *) {
+ qWarning("Authentication required for downloading favicon.");
+ });
+ QObject::connect(&WebView::networkAccessManager(), &QNetworkAccessManager::proxyAuthenticationRequired,
+ [](const QNetworkProxy &, QAuthenticator *) {
+ qWarning("Proxy authentication required for downloading favicon.");
+ });
+}
+
+Browser::~Browser()
+{
+ qDeleteAll(m_windows);
+ m_windows.clear();
+}
+
+Browser &Browser::instance()
+{
+ static Browser browser;
+ return browser;
+}
+
+QVector<BrowserWindow*> Browser::windows()
+{
+ return m_windows;
+}
+
+void Browser::addWindow(BrowserWindow *mainWindow)
+{
+ if (m_windows.contains(mainWindow))
+ return;
+ m_windows.prepend(mainWindow);
+ QObject::connect(mainWindow, &QObject::destroyed, [this, mainWindow]() {
+ m_windows.removeOne(mainWindow);
+ });
+ mainWindow->show();
+}
+
diff --git a/examples/webenginewidgets/simplebrowser/browser.h b/examples/webenginewidgets/simplebrowser/browser.h
new file mode 100644
index 000000000..0fdbd46a7
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/browser.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef BROWSER_H
+#define BROWSER_H
+
+#include <QVector>
+
+class BrowserWindow;
+
+class Browser
+{
+public:
+ ~Browser();
+
+ QVector<BrowserWindow*> windows();
+ void addWindow(BrowserWindow* window);
+ static Browser &instance();
+
+private:
+ Browser();
+ QVector<BrowserWindow*> m_windows;
+};
+#endif // BROWSER_H
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.cpp b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
new file mode 100644
index 000000000..e7d5fd129
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.cpp
@@ -0,0 +1,437 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "browser.h"
+#include "browserwindow.h"
+#include "tabwidget.h"
+#include "urllineedit.h"
+#include "webview.h"
+#include <QApplication>
+#include <QCloseEvent>
+#include <QDesktopWidget>
+#include <QFileDialog>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QProgressBar>
+#include <QStatusBar>
+#include <QToolBar>
+#include <QVBoxLayout>
+
+BrowserWindow::BrowserWindow(QWidget *parent, Qt::WindowFlags flags)
+ : QMainWindow(parent, flags)
+ , m_tabWidget(new TabWidget(this))
+ , m_progressBar(new QProgressBar(this))
+ , m_historyBackAction(nullptr)
+ , m_historyForwardAction(nullptr)
+ , m_stopAction(nullptr)
+ , m_reloadAction(nullptr)
+ , m_stopReloadAction(nullptr)
+ , m_urlLineEdit(new UrlLineEdit(this))
+{
+ setToolButtonStyle(Qt::ToolButtonFollowStyle);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ QToolBar *toolbar = createToolBar();
+ addToolBar(toolbar);
+ menuBar()->addMenu(createFileMenu(m_tabWidget));
+ menuBar()->addMenu(createViewMenu(toolbar));
+ menuBar()->addMenu(createWindowMenu(m_tabWidget));
+ menuBar()->addMenu(createHelpMenu());
+
+ QWidget *centralWidget = new QWidget(this);
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setSpacing(0);
+ layout->setMargin(0);
+ addToolBarBreak();
+
+ m_progressBar->setMaximumHeight(1);
+ m_progressBar->setTextVisible(false);
+ m_progressBar->setStyleSheet(QStringLiteral("QProgressBar {border: 0px } QProgressBar::chunk { background-color: red; }"));
+
+ layout->addWidget(m_progressBar);
+ layout->addWidget(m_tabWidget);
+ centralWidget->setLayout(layout);
+ setCentralWidget(centralWidget);
+
+ connect(m_tabWidget, &TabWidget::titleChanged, this, &BrowserWindow::handleWebViewTitleChanged);
+ connect(m_tabWidget, &TabWidget::linkHovered, [this](const QString& url) {
+ statusBar()->showMessage(url);
+ });
+ connect(m_tabWidget, &TabWidget::loadProgress, this, &BrowserWindow::handleWebViewLoadProgress);
+ connect(m_tabWidget, &TabWidget::urlChanged, this, &BrowserWindow::handleWebViewUrlChanged);
+ connect(m_tabWidget, &TabWidget::iconChanged, this, &BrowserWindow::handleWebViewIconChanged);
+ connect(m_tabWidget, &TabWidget::webActionEnabledChanged, this, &BrowserWindow::handleWebActionEnabledChanged);
+ connect(m_urlLineEdit, &QLineEdit::returnPressed, this, [this]() {
+ m_urlLineEdit->setFavIcon(QIcon(QStringLiteral(":defaulticon.png")));
+ loadPage(m_urlLineEdit->url());
+ });
+
+ m_urlLineEdit->setFavIcon(QIcon(QStringLiteral(":defaulticon.png")));
+
+ handleWebViewTitleChanged(tr("Qt Simple Browser"));
+ m_tabWidget->createTab();
+}
+
+BrowserWindow::~BrowserWindow()
+{
+}
+
+QSize BrowserWindow::sizeHint() const
+{
+ QRect desktopRect = QApplication::desktop()->screenGeometry();
+ QSize size = desktopRect.size() * qreal(0.9);
+ return size;
+}
+
+QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget)
+{
+ QMenu *fileMenu = new QMenu(tr("&File"));
+ fileMenu->addAction(tr("&New Window"), this, &BrowserWindow::handleNewWindowTriggered, QKeySequence::New);
+
+ QAction *newTabAction = new QAction(QIcon(QLatin1String(":addtab.png")), tr("New &Tab"), this);
+ newTabAction->setShortcuts(QKeySequence::AddTab);
+ newTabAction->setIconVisibleInMenu(false);
+ connect(newTabAction, &QAction::triggered, tabWidget, &TabWidget::createTab);
+ fileMenu->addAction(newTabAction);
+
+ fileMenu->addAction(tr("&Open File..."), this, &BrowserWindow::handleFileOpenTriggered, QKeySequence::Open);
+ fileMenu->addSeparator();
+
+ QAction *closeTabAction = new QAction(QIcon(QLatin1String(":closetab.png")), tr("&Close Tab"), this);
+ closeTabAction->setShortcuts(QKeySequence::Close);
+ closeTabAction->setIconVisibleInMenu(false);
+ connect(closeTabAction, &QAction::triggered, [tabWidget]() {
+ tabWidget->closeTab(tabWidget->currentIndex());
+ });
+ fileMenu->addAction(closeTabAction);
+
+ QAction *closeAction = new QAction(tr("&Quit"),this);
+ closeAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
+ connect(closeAction, &QAction::triggered, this, &QWidget::close);
+ fileMenu->addAction(closeAction);
+
+ connect(fileMenu, &QMenu::aboutToShow, [closeAction]() {
+ if (Browser::instance().windows().count() == 1)
+ closeAction->setText(tr("&Quit"));
+ else
+ closeAction->setText(tr("&Close Window"));
+ });
+ return fileMenu;
+}
+
+QMenu *BrowserWindow::createViewMenu(QToolBar *toolbar)
+{
+ QMenu *viewMenu = new QMenu(tr("&View"));
+ m_stopAction = viewMenu->addAction(tr("&Stop"));
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Period));
+ shortcuts.append(Qt::Key_Escape);
+ m_stopAction->setShortcuts(shortcuts);
+ connect(m_stopAction, &QAction::triggered, [this]() {
+ m_tabWidget->triggerWebPageAction(QWebEnginePage::Stop);
+ });
+
+ m_reloadAction = viewMenu->addAction(tr("Reload Page"));
+ m_reloadAction->setShortcuts(QKeySequence::Refresh);
+ connect(m_reloadAction, &QAction::triggered, [this]() {
+ m_tabWidget->triggerWebPageAction(QWebEnginePage::Reload);
+ });
+
+ QAction *zoomIn = viewMenu->addAction(tr("Zoom &In"));
+ zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
+ connect(zoomIn, &QAction::triggered, [this]() {
+ if (currentTab())
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() + 0.1);
+ });
+
+ QAction *zoomOut = viewMenu->addAction(tr("Zoom &Out"));
+ zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
+ connect(zoomOut, &QAction::triggered, [this]() {
+ if (currentTab())
+ currentTab()->setZoomFactor(currentTab()->zoomFactor() - 0.1);
+ });
+
+ QAction *resetZoom = viewMenu->addAction(tr("Reset &Zoom"));
+ resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
+ connect(resetZoom, &QAction::triggered, [this]() {
+ if (currentTab())
+ currentTab()->setZoomFactor(1.0);
+ });
+
+
+ viewMenu->addSeparator();
+ QAction *viewToolbarAction = new QAction(tr("Hide Toolbar"),this);
+ viewToolbarAction->setShortcut(tr("Ctrl+|"));
+ connect(viewToolbarAction, &QAction::triggered, [toolbar,viewToolbarAction]() {
+ if (toolbar->isVisible()) {
+ viewToolbarAction->setText(tr("Show Toolbar"));
+ toolbar->close();
+ } else {
+ viewToolbarAction->setText(tr("Hide Toolbar"));
+ toolbar->show();
+ }
+ });
+ viewMenu->addAction(viewToolbarAction);
+
+ QAction *viewStatusbarAction = new QAction(tr("Hide Status Bar"), this);
+ viewStatusbarAction->setShortcut(tr("Ctrl+/"));
+ connect(viewStatusbarAction, &QAction::triggered, [this, viewStatusbarAction]() {
+ if (statusBar()->isVisible()) {
+ viewStatusbarAction->setText(tr("Show Status Bar"));
+ statusBar()->close();
+ } else {
+ viewStatusbarAction->setText(tr("Hide Status Bar"));
+ statusBar()->show();
+ }
+ });
+ viewMenu->addAction(viewStatusbarAction);
+ return viewMenu;
+}
+
+QMenu *BrowserWindow::createWindowMenu(TabWidget *tabWidget)
+{
+ QMenu *menu = new QMenu(tr("&Window"));
+
+ QAction *nextTabAction = new QAction(tr("Show Next Tab"), this);
+ QList<QKeySequence> shortcuts;
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
+ nextTabAction->setShortcuts(shortcuts);
+ connect(nextTabAction, &QAction::triggered, tabWidget, &TabWidget::nextTab);
+
+ QAction *previousTabAction = new QAction(tr("Show Previous Tab"), this);
+ shortcuts.clear();
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
+ shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
+ previousTabAction->setShortcuts(shortcuts);
+ connect(previousTabAction, &QAction::triggered, tabWidget, &TabWidget::previousTab);
+
+ connect(menu, &QMenu::aboutToShow, [this, menu, nextTabAction, previousTabAction]() {
+ menu->clear();
+ menu->addAction(nextTabAction);
+ menu->addAction(previousTabAction);
+ menu->addSeparator();
+
+ QVector<BrowserWindow*> windows = Browser::instance().windows();
+ int index(-1);
+ for (auto window : windows) {
+ QAction *action = menu->addAction(window->windowTitle(), this, &BrowserWindow::handleShowWindowTriggered);
+ action->setData(++index);
+ action->setCheckable(true);
+ if (window == this)
+ action->setChecked(true);
+ }
+ });
+ return menu;
+}
+
+QMenu *BrowserWindow::createHelpMenu()
+{
+ QMenu *helpMenu = new QMenu(tr("&Help"));
+ helpMenu->addAction(tr("About &Qt"), qApp, QApplication::aboutQt);
+ return helpMenu;
+}
+
+QToolBar *BrowserWindow::createToolBar()
+{
+ QToolBar *navigationBar = new QToolBar(tr("Navigation"));
+ navigationBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
+ navigationBar->toggleViewAction()->setEnabled(false);
+
+ m_historyBackAction = new QAction(this);
+ m_historyBackAction->setShortcuts(QKeySequence::Back);
+ m_historyBackAction->setIconVisibleInMenu(false);
+ m_historyBackAction->setIcon(QIcon(QStringLiteral(":go-previous.png")));
+ connect(m_historyBackAction, &QAction::triggered, [this]() {
+ m_tabWidget->triggerWebPageAction(QWebEnginePage::Back);
+ });
+ navigationBar->addAction(m_historyBackAction);
+
+ m_historyForwardAction = new QAction(this);
+ m_historyForwardAction->setShortcuts(QKeySequence::Forward);
+ m_historyForwardAction->setIconVisibleInMenu(false);
+ m_historyForwardAction->setIcon(QIcon(QStringLiteral(":go-next.png")));
+ connect(m_historyForwardAction, &QAction::triggered, [this]() {
+ m_tabWidget->triggerWebPageAction(QWebEnginePage::Forward);
+ });
+ navigationBar->addAction(m_historyForwardAction);
+
+ m_stopReloadAction = new QAction(this);
+ connect(m_stopReloadAction, &QAction::triggered, [this]() {
+ m_tabWidget->triggerWebPageAction(QWebEnginePage::WebAction(m_stopReloadAction->data().toInt()));
+ });
+ navigationBar->addAction(m_stopReloadAction);
+ navigationBar->addWidget(m_urlLineEdit);
+ int size = m_urlLineEdit->sizeHint().height();
+ navigationBar->setIconSize(QSize(size, size));
+ return navigationBar;
+}
+
+void BrowserWindow::handleWebViewIconChanged(const QIcon &icon)
+{
+ m_urlLineEdit->setFavIcon(icon);
+}
+
+void BrowserWindow::handleWebViewUrlChanged(const QUrl &url)
+{
+ m_urlLineEdit->setUrl(url);
+ if (url.isEmpty())
+ m_urlLineEdit->setFocus();
+}
+
+void BrowserWindow::handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled)
+{
+ switch (action) {
+ case QWebEnginePage::Back:
+ m_historyBackAction->setEnabled(enabled);
+ break;
+ case QWebEnginePage::Forward:
+ m_historyForwardAction->setEnabled(enabled);
+ break;
+ case QWebEnginePage::Reload:
+ m_reloadAction->setEnabled(enabled);
+ break;
+ case QWebEnginePage::Stop:
+ m_stopAction->setEnabled(enabled);
+ break;
+ default:
+ qWarning("Unhandled webActionChanged singal");
+ }
+}
+
+void BrowserWindow::handleWebViewTitleChanged(const QString &title)
+{
+ if (title.isEmpty())
+ setWindowTitle(tr("Qt Simple Browser"));
+ else
+ setWindowTitle(tr("%1 - Qt Simple Browser").arg(title));
+}
+
+void BrowserWindow::handleNewWindowTriggered()
+{
+ BrowserWindow *window = new BrowserWindow();
+ Browser::instance().addWindow(window);
+ window->loadHomePage();
+}
+
+void BrowserWindow::handleFileOpenTriggered()
+{
+ QString file = QFileDialog::getOpenFileName(this, tr("Open Web Resource"), QString(),
+ tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));
+ if (file.isEmpty())
+ return;
+ loadPage(file);
+}
+
+void BrowserWindow::closeEvent(QCloseEvent *event)
+{
+ if (m_tabWidget->count() > 1) {
+ int ret = QMessageBox::warning(this, tr("Confirm close"),
+ tr("Are you sure you want to close the window ?\n"
+ "There are %1 tabs open.").arg(m_tabWidget->count()),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+ if (ret == QMessageBox::No) {
+ event->ignore();
+ return;
+ }
+ }
+ event->accept();
+ deleteLater();
+}
+
+
+void BrowserWindow::loadHomePage()
+{
+ loadPage(QStringLiteral("http://www.qt.io"));
+}
+
+void BrowserWindow::loadPage(const QString &page)
+{
+ loadPage(QUrl::fromUserInput(page));
+}
+
+void BrowserWindow::loadPage(const QUrl &url)
+{
+ if (url.isValid()) {
+ m_urlLineEdit->setUrl(url);
+ m_tabWidget->setUrl(url);
+ }
+}
+
+TabWidget *BrowserWindow::tabWidget() const
+{
+ return m_tabWidget;
+}
+
+WebView *BrowserWindow::currentTab() const
+{
+ return m_tabWidget->currentWebView();
+}
+
+void BrowserWindow::handleWebViewLoadProgress(int progress)
+{
+ static QIcon stopIcon(QStringLiteral(":process-stop.png"));
+ static QIcon reloadIcon(QStringLiteral(":view-refresh.png"));
+
+ if (progress < 100 && progress > 0) {
+ m_stopReloadAction->setData(QWebEnginePage::Stop);
+ m_stopReloadAction->setIcon(stopIcon);
+ m_stopReloadAction->setToolTip(tr("Stop loading the current page"));
+ } else {
+ m_stopReloadAction->setData(QWebEnginePage::Reload);
+ m_stopReloadAction->setIcon(reloadIcon);
+ m_stopReloadAction->setToolTip(tr("Reload the current page"));
+ }
+ m_progressBar->setValue(progress < 100 ? progress : 0);
+}
+
+void BrowserWindow::handleShowWindowTriggered()
+{
+ if (QAction *action = qobject_cast<QAction*>(sender())) {
+ int offset = action->data().toInt();
+ QVector<BrowserWindow*> windows = Browser::instance().windows();
+ windows.at(offset)->activateWindow();
+ windows.at(offset)->currentTab()->setFocus();
+ }
+}
diff --git a/examples/webenginewidgets/simplebrowser/browserwindow.h b/examples/webenginewidgets/simplebrowser/browserwindow.h
new file mode 100644
index 000000000..c947bed1d
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/browserwindow.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef BROWSERWINDOW_H
+#define BROWSERWINDOW_H
+
+#include <QMainWindow>
+#include <QWebEnginePage>
+
+QT_BEGIN_NAMESPACE
+class QProgressBar;
+QT_END_NAMESPACE
+
+class TabWidget;
+class UrlLineEdit;
+class WebView;
+
+class BrowserWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ BrowserWindow(QWidget *parent = nullptr, Qt::WindowFlags flags = 0);
+ ~BrowserWindow();
+ QSize sizeHint() const override;
+ TabWidget *tabWidget() const;
+ WebView *currentTab() const;
+
+ void loadPage(const QString &url);
+ void loadPage(const QUrl &url);
+ void loadHomePage();
+
+protected:
+ void closeEvent(QCloseEvent *event) override;
+
+private slots:
+ void handleNewWindowTriggered();
+ void handleFileOpenTriggered();
+ void handleShowWindowTriggered();
+ void handleWebViewLoadProgress(int);
+ void handleWebViewTitleChanged(const QString &title);
+ void handleWebViewUrlChanged(const QUrl &url);
+ void handleWebViewIconChanged(const QIcon &icon);
+ void handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
+
+private:
+ QMenu *createFileMenu(TabWidget *tabWidget);
+ QMenu *createViewMenu(QToolBar *toolBar);
+ QMenu *createWindowMenu(TabWidget *tabWidget);
+ QMenu *createHelpMenu();
+ QToolBar *createToolBar();
+
+private:
+ TabWidget *m_tabWidget;
+ QProgressBar *m_progressBar;
+ QAction *m_historyBackAction;
+ QAction *m_historyForwardAction;
+ QAction *m_stopAction;
+ QAction *m_reloadAction;
+ QAction *m_stopReloadAction;
+ UrlLineEdit *m_urlLineEdit;
+};
+
+#endif // BROWSERWINDOW_H
diff --git a/examples/webenginewidgets/simplebrowser/certificateerrordialog.ui b/examples/webenginewidgets/simplebrowser/certificateerrordialog.ui
new file mode 100644
index 000000000..a97f25b6e
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/certificateerrordialog.ui
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>CertificateErrorDialog</class>
+ <widget class="QDialog" name="CertificateErrorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>370</width>
+ <height>141</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>20</number>
+ </property>
+ <property name="rightMargin">
+ <number>20</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="m_iconLabel">
+ <property name="text">
+ <string>Icon</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="m_errorLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Error</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="m_infoLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>If you wish so, you may continue with an unverified certificate. Accepting an unverified certificate mean you may not be connected with the host you tried to connect to.
+
+Do you wish to override the security check and continue ? </string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::No|QDialogButtonBox::Yes</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>CertificateErrorDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>CertificateErrorDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webenginewidgets/simplebrowser/data/addtab.png b/examples/webenginewidgets/simplebrowser/data/addtab.png
new file mode 100644
index 000000000..20928fb40
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/addtab.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/closetab.png b/examples/webenginewidgets/simplebrowser/data/closetab.png
new file mode 100644
index 000000000..ab9d669ee
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/closetab.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/defaulticon.png b/examples/webenginewidgets/simplebrowser/data/defaulticon.png
new file mode 100644
index 000000000..01a0920c9
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/defaulticon.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/go-next.png b/examples/webenginewidgets/simplebrowser/data/go-next.png
new file mode 100644
index 000000000..6f3f65d33
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/go-next.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/go-previous.png b/examples/webenginewidgets/simplebrowser/data/go-previous.png
new file mode 100644
index 000000000..93be3d1ee
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/go-previous.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/process-stop.png b/examples/webenginewidgets/simplebrowser/data/process-stop.png
new file mode 100644
index 000000000..b68290bf1
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/process-stop.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/data/simplebrowser.qrc b/examples/webenginewidgets/simplebrowser/data/simplebrowser.qrc
new file mode 100644
index 000000000..5795063ca
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/simplebrowser.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/">
+ <file>addtab.png</file>
+ <file>defaulticon.png</file>
+ <file>closetab.png</file>
+ <file>go-next.png</file>
+ <file>go-previous.png</file>
+ <file>process-stop.png</file>
+ <file>simplebrowser.svg</file>
+ <file>view-refresh.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/webenginewidgets/simplebrowser/data/simplebrowser.svg b/examples/webenginewidgets/simplebrowser/data/simplebrowser.svg
new file mode 100644
index 000000000..9f39deb66
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/simplebrowser.svg
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 19.2.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="94px" height="94px" viewBox="0 0 94 94" enable-background="new 0 0 94 94" xml:space="preserve">
+<g>
+ <circle fill="none" cx="47" cy="47" r="47"/>
+ <g>
+ <path fill="#46A2DA" d="M47,92.979c-11.779,0-23.559-4.484-32.526-13.451C-3.461,61.591-3.461,32.409,14.472,14.474
+ C32.41-3.463,61.592-3.461,79.526,14.473c17.935,17.936,17.935,47.119,0.002,65.054l-0.002,0.001
+ C70.559,88.495,58.779,92.979,47,92.979z"/>
+ </g>
+ <path fill="#80C342" d="M93,47C93,21.595,72.405,1,47,1C34.297,1,22.797,6.149,14.473,14.473l65.054,65.054
+ C87.851,71.203,93,59.703,93,47z"/>
+ <g>
+ <path fill="#46A2DA" d="M47,65c-4.808,0-9.328-1.873-12.728-5.272c-7.018-7.019-7.018-18.438,0-25.456
+ C37.672,30.873,42.192,29,47,29s9.328,1.873,12.728,5.272c7.018,7.019,7.018,18.438,0,25.456C56.328,63.127,51.808,65,47,65z"/>
+ <path fill="#FFFFFF" d="M62.248,59.919c6.671-7.858,6.312-19.644-1.105-27.061C57.237,28.953,52.118,27,47,27
+ c-5.118,0-10.237,1.953-14.142,5.858c-7.81,7.81-7.81,20.474,0,28.284C36.763,65.047,41.882,67,47,67
+ c4.379,0,8.752-1.441,12.372-4.3L77.88,81.209c0.989-0.895,1.935-1.837,2.843-2.814L62.248,59.919z M35.686,58.314
+ c-6.238-6.238-6.238-16.389,0-22.627C38.708,32.664,42.726,31,47,31c4.274,0,8.292,1.664,11.314,4.686
+ c6.238,6.238,6.238,16.389,0,22.627C55.292,61.336,51.274,63,47,63C42.726,63,38.708,61.336,35.686,58.314z"/>
+ </g>
+</g>
+</svg>
diff --git a/examples/webenginewidgets/simplebrowser/data/view-refresh.png b/examples/webenginewidgets/simplebrowser/data/view-refresh.png
new file mode 100644
index 000000000..cab4d02c7
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/data/view-refresh.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png
new file mode 100644
index 000000000..2a1abce50
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png
new file mode 100644
index 000000000..777309075
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png
Binary files differ
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser-model.qmodel b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser-model.qmodel
new file mode 100644
index 000000000..ce6f8ea2a
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser-model.qmodel
@@ -0,0 +1,938 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<qmt>
+ <project>
+ <uid>{fa2cc127-337e-4194-b272-fc8bb6c1e3b0}</uid>
+ <root-package>
+ <instance>
+ <MPackage>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{4ffa8932-4330-4845-af33-c26f0fcdecd7}</uid>
+ </MElement>
+ </base-MElement>
+ <name>simplebrowser-model</name>
+ <children>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{de670101-4064-4a81-bdf0-885b4cb09526}</uid>
+ <target>
+ <instance type="MCanvasDiagram">
+ <MCanvasDiagram>
+ <base-MDiagram>
+ <MDiagram>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{de670101-4064-4a81-bdf0-885b4cb09526}</uid>
+ </MElement>
+ </base-MElement>
+ <name>simplebrowser-model</name>
+ </MObject>
+ </base-MObject>
+ <elements>
+ <qlist>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{b7b131f9-5e56-484a-ba8b-c7a5fc34fb7b}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</object>
+ <name>BrowserWindow</name>
+ <pos>x:190;y:100</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{8d3e6a00-ffa6-497a-a5a2-f1ba13deee76}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{72a2b731-3aad-430f-a76c-f43dd9b36462}</object>
+ <name>Browser</name>
+ <pos>x:5;y:100</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DAssociation">
+ <DAssociation>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{5ab59ef4-3509-4ea3-900e-20d1cea16af1}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{e878ee71-b5d1-4943-b081-466851b0f721}</object>
+ <a>{8d3e6a00-ffa6-497a-a5a2-f1ba13deee76}</a>
+ <b>{b7b131f9-5e56-484a-ba8b-c7a5fc34fb7b}</b>
+ </DRelation>
+ </base-DRelation>
+ <a>
+ <DAssociationEnd>
+ <cradinality>1..*</cradinality>
+ <kind>2</kind>
+ </DAssociationEnd>
+ </a>
+ <b>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </b>
+ </DAssociation>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{487d395c-3f8b-422c-9568-d70a5d50a9d4}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{1ab2b778-127b-4661-ba2d-8f329f44d859}</object>
+ <name>TabWidget</name>
+ <pos>x:360;y:100</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DAssociation">
+ <DAssociation>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{cc9dee75-9f9c-4599-acf8-35e14f75cd78}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{ee3a86b4-773d-4ea5-81c1-552501061629}</object>
+ <a>{b7b131f9-5e56-484a-ba8b-c7a5fc34fb7b}</a>
+ <b>{487d395c-3f8b-422c-9568-d70a5d50a9d4}</b>
+ </DRelation>
+ </base-DRelation>
+ <a>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </a>
+ <b>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </b>
+ </DAssociation>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{9d909ab7-02a8-4582-89cd-b31bb794bc40}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</object>
+ <name>WebView</name>
+ <pos>x:550;y:100</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DAssociation">
+ <DAssociation>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{1e82e3ce-c835-4b7a-99ec-ae40e07f0185}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{97fd8235-200e-4448-b173-51add1df8edc}</object>
+ <a>{487d395c-3f8b-422c-9568-d70a5d50a9d4}</a>
+ <b>{9d909ab7-02a8-4582-89cd-b31bb794bc40}</b>
+ </DRelation>
+ </base-DRelation>
+ <a>
+ <DAssociationEnd>
+ <cradinality>1..*</cradinality>
+ <kind>2</kind>
+ </DAssociationEnd>
+ </a>
+ <b>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </b>
+ </DAssociation>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{ed0a94cd-0abd-49f6-ac98-3da13fef9dff}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{320f3a48-12de-4bcb-b7f5-47b12c77dbee}</object>
+ <name>WebPage</name>
+ <pos>x:720;y:100</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DAssociation">
+ <DAssociation>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{06ce5b46-b043-45b8-8718-0054d7baf939}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{772227ff-d0df-4ecd-97ea-89d1bd10a96f}</object>
+ <a>{9d909ab7-02a8-4582-89cd-b31bb794bc40}</a>
+ <b>{ed0a94cd-0abd-49f6-ac98-3da13fef9dff}</b>
+ </DRelation>
+ </base-DRelation>
+ <a>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </a>
+ <b>
+ <DAssociationEnd>
+ <cradinality>1</cradinality>
+ </DAssociationEnd>
+ </b>
+ </DAssociation>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{cb588414-35d6-482f-a9df-2dddb7d72af1}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{9b91aa7b-0fa3-4c78-9e8d-e1bfdfce9f7f}</object>
+ <name>QWebEngineView</name>
+ <pos>x:550;y:0</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{c9755d3b-0ed4-4821-95d3-64f4f4cdb458}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{6659de40-605d-4744-8654-73ae959dcb8a}</object>
+ <name>QWebEnginePage</name>
+ <pos>x:720;y:0</pos>
+ <rect>x:-50;y:-30;w:100;h:60</rect>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DInheritance">
+ <DInheritance>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{6bdcd7e9-fa78-417d-9024-47796596e18d}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{1176aee6-be27-4b21-be22-33bca908a71e}</object>
+ <a>{9d909ab7-02a8-4582-89cd-b31bb794bc40}</a>
+ <b>{cb588414-35d6-482f-a9df-2dddb7d72af1}</b>
+ </DRelation>
+ </base-DRelation>
+ </DInheritance>
+ </instance>
+ </item>
+ <item>
+ <instance type="DInheritance">
+ <DInheritance>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{30abce68-7fa1-4b0c-8620-9f96c7392be7}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{20788ccc-cab0-406b-8cf4-d8062570085e}</object>
+ <a>{ed0a94cd-0abd-49f6-ac98-3da13fef9dff}</a>
+ <b>{c9755d3b-0ed4-4821-95d3-64f4f4cdb458}</b>
+ </DRelation>
+ </base-DRelation>
+ </DInheritance>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{a372397b-316a-48c0-b99f-724372413a64}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{32e677d2-4bfb-4f5d-93dc-67fdb1a0c8a1}</object>
+ <name>QTabWidget</name>
+ <pos>x:360;y:0</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DInheritance">
+ <DInheritance>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{dce2499c-fdef-40e3-ba77-29b94f8beb1b}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{66fd2699-e4ea-4312-990a-7488c75fc850}</object>
+ <a>{487d395c-3f8b-422c-9568-d70a5d50a9d4}</a>
+ <b>{a372397b-316a-48c0-b99f-724372413a64}</b>
+ </DRelation>
+ </base-DRelation>
+ </DInheritance>
+ </instance>
+ </item>
+ <item>
+ <instance type="DClass">
+ <DClass>
+ <base-DObject>
+ <DObject>
+ <base-DElement>
+ <DElement>
+ <uid>{35e8a91e-8192-4e17-b6c7-e44b3ba3a138}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{988c1b8e-1e9a-4d03-b9b4-75ba5dcac6d7}</object>
+ <name>QMainWindow</name>
+ <pos>x:190;y:0</pos>
+ <rect>x:-55;y:-30;w:110;h:60</rect>
+ <auto-sized>false</auto-sized>
+ <visual-role>0</visual-role>
+ </DObject>
+ </base-DObject>
+ </DClass>
+ </instance>
+ </item>
+ <item>
+ <instance type="DInheritance">
+ <DInheritance>
+ <base-DRelation>
+ <DRelation>
+ <base-DElement>
+ <DElement>
+ <uid>{7dd17b0c-4256-463f-8852-c4faf0614997}</uid>
+ </DElement>
+ </base-DElement>
+ <object>{9f29593e-b0b5-4488-ae5d-2378857535a0}</object>
+ <a>{b7b131f9-5e56-484a-ba8b-c7a5fc34fb7b}</a>
+ <b>{35e8a91e-8192-4e17-b6c7-e44b3ba3a138}</b>
+ </DRelation>
+ </base-DRelation>
+ </DInheritance>
+ </instance>
+ </item>
+ </qlist>
+ </elements>
+ <last-modified>1456935246527</last-modified>
+ </MDiagram>
+ </base-MDiagram>
+ </MCanvasDiagram>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{72a2b731-3aad-430f-a76c-f43dd9b36462}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{72a2b731-3aad-430f-a76c-f43dd9b36462}</uid>
+ <flags>1</flags>
+ </MElement>
+ </base-MElement>
+ <name>Browser</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{736a9cc9-35f1-47c1-bdc4-c3033d14a33d}</uid>
+ <target>
+ <instance type="MDependency">
+ <MDependency>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{736a9cc9-35f1-47c1-bdc4-c3033d14a33d}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{72a2b731-3aad-430f-a76c-f43dd9b36462}</a>
+ <b>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</b>
+ </MRelation>
+ </base-MRelation>
+ </MDependency>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{e878ee71-b5d1-4943-b081-466851b0f721}</uid>
+ <target>
+ <instance type="MAssociation">
+ <MAssociation>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{e878ee71-b5d1-4943-b081-466851b0f721}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{72a2b731-3aad-430f-a76c-f43dd9b36462}</a>
+ <b>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</b>
+ </MRelation>
+ </base-MRelation>
+ <a>
+ <MAssociationEnd>
+ <cardinality>1..*</cardinality>
+ <kind>2</kind>
+ </MAssociationEnd>
+ </a>
+ <b>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </b>
+ </MAssociation>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</uid>
+ <flags>1</flags>
+ </MElement>
+ </base-MElement>
+ <name>BrowserWindow</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{ee3a86b4-773d-4ea5-81c1-552501061629}</uid>
+ <target>
+ <instance type="MAssociation">
+ <MAssociation>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{ee3a86b4-773d-4ea5-81c1-552501061629}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</a>
+ <b>{1ab2b778-127b-4661-ba2d-8f329f44d859}</b>
+ </MRelation>
+ </base-MRelation>
+ <a>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </a>
+ <b>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </b>
+ </MAssociation>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{9f29593e-b0b5-4488-ae5d-2378857535a0}</uid>
+ <target>
+ <instance type="MInheritance">
+ <MInheritance>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{9f29593e-b0b5-4488-ae5d-2378857535a0}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{ee93b67f-4caf-4d92-9303-f6c2582bf1b9}</a>
+ <b>{988c1b8e-1e9a-4d03-b9b4-75ba5dcac6d7}</b>
+ </MRelation>
+ </base-MRelation>
+ </MInheritance>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{1ab2b778-127b-4661-ba2d-8f329f44d859}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{1ab2b778-127b-4661-ba2d-8f329f44d859}</uid>
+ <flags>1</flags>
+ </MElement>
+ </base-MElement>
+ <name>TabWidget</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{97fd8235-200e-4448-b173-51add1df8edc}</uid>
+ <target>
+ <instance type="MAssociation">
+ <MAssociation>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{97fd8235-200e-4448-b173-51add1df8edc}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{1ab2b778-127b-4661-ba2d-8f329f44d859}</a>
+ <b>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</b>
+ </MRelation>
+ </base-MRelation>
+ <a>
+ <MAssociationEnd>
+ <cardinality>1..*</cardinality>
+ <kind>2</kind>
+ </MAssociationEnd>
+ </a>
+ <b>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </b>
+ </MAssociation>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{66fd2699-e4ea-4312-990a-7488c75fc850}</uid>
+ <target>
+ <instance type="MInheritance">
+ <MInheritance>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{66fd2699-e4ea-4312-990a-7488c75fc850}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{1ab2b778-127b-4661-ba2d-8f329f44d859}</a>
+ <b>{32e677d2-4bfb-4f5d-93dc-67fdb1a0c8a1}</b>
+ </MRelation>
+ </base-MRelation>
+ </MInheritance>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{320f3a48-12de-4bcb-b7f5-47b12c77dbee}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{320f3a48-12de-4bcb-b7f5-47b12c77dbee}</uid>
+ <flags>1</flags>
+ </MElement>
+ </base-MElement>
+ <name>WebPage</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{20788ccc-cab0-406b-8cf4-d8062570085e}</uid>
+ <target>
+ <instance type="MInheritance">
+ <MInheritance>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{20788ccc-cab0-406b-8cf4-d8062570085e}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{320f3a48-12de-4bcb-b7f5-47b12c77dbee}</a>
+ <b>{6659de40-605d-4744-8654-73ae959dcb8a}</b>
+ </MRelation>
+ </base-MRelation>
+ </MInheritance>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</uid>
+ <flags>1</flags>
+ </MElement>
+ </base-MElement>
+ <name>WebView</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{772227ff-d0df-4ecd-97ea-89d1bd10a96f}</uid>
+ <target>
+ <instance type="MAssociation">
+ <MAssociation>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{772227ff-d0df-4ecd-97ea-89d1bd10a96f}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</a>
+ <b>{320f3a48-12de-4bcb-b7f5-47b12c77dbee}</b>
+ </MRelation>
+ </base-MRelation>
+ <a>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </a>
+ <b>
+ <MAssociationEnd>
+ <cardinality>1</cardinality>
+ </MAssociationEnd>
+ </b>
+ </MAssociation>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{1176aee6-be27-4b21-be22-33bca908a71e}</uid>
+ <target>
+ <instance type="MInheritance">
+ <MInheritance>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{1176aee6-be27-4b21-be22-33bca908a71e}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</a>
+ <b>{9b91aa7b-0fa3-4c78-9e8d-e1bfdfce9f7f}</b>
+ </MRelation>
+ </base-MRelation>
+ </MInheritance>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{9b91aa7b-0fa3-4c78-9e8d-e1bfdfce9f7f}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{9b91aa7b-0fa3-4c78-9e8d-e1bfdfce9f7f}</uid>
+ </MElement>
+ </base-MElement>
+ <name>QWebEngineView</name>
+ <relations>
+ <handles>
+ <handles>
+ <qlist>
+ <item>
+ <handle>
+ <uid>{5124d95d-73fb-4d70-aa89-1135f2202c2f}</uid>
+ <target>
+ <instance type="MInheritance">
+ <MInheritance>
+ <base-MRelation>
+ <MRelation>
+ <base-MElement>
+ <MElement>
+ <uid>{5124d95d-73fb-4d70-aa89-1135f2202c2f}</uid>
+ </MElement>
+ </base-MElement>
+ <a>{9b91aa7b-0fa3-4c78-9e8d-e1bfdfce9f7f}</a>
+ <b>{b8a281e2-4ee3-42cd-bb3d-d075a54ad358}</b>
+ </MRelation>
+ </base-MRelation>
+ </MInheritance>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </relations>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{6659de40-605d-4744-8654-73ae959dcb8a}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{6659de40-605d-4744-8654-73ae959dcb8a}</uid>
+ </MElement>
+ </base-MElement>
+ <name>QWebEnginePage</name>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{32e677d2-4bfb-4f5d-93dc-67fdb1a0c8a1}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{32e677d2-4bfb-4f5d-93dc-67fdb1a0c8a1}</uid>
+ </MElement>
+ </base-MElement>
+ <name>QTabWidget</name>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ <item>
+ <handle>
+ <uid>{988c1b8e-1e9a-4d03-b9b4-75ba5dcac6d7}</uid>
+ <target>
+ <instance type="MClass">
+ <MClass>
+ <base-MObject>
+ <MObject>
+ <base-MElement>
+ <MElement>
+ <uid>{988c1b8e-1e9a-4d03-b9b4-75ba5dcac6d7}</uid>
+ </MElement>
+ </base-MElement>
+ <name>QMainWindow</name>
+ </MObject>
+ </base-MObject>
+ </MClass>
+ </instance>
+ </target>
+ </handle>
+ </item>
+ </qlist>
+ </handles>
+ </handles>
+ </children>
+ </MObject>
+ </base-MObject>
+ </MPackage>
+ </instance>
+ </root-package>
+ </project>
+</qmt>
diff --git a/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
new file mode 100644
index 000000000..b8df9b02a
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/doc/src/simplebrowser.qdoc
@@ -0,0 +1,263 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://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 http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://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: http://www.gnu.org/copyleft/fdl.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example webenginewidgets/simplebrowser
+ \title WebEngine Widgets Simple Browser Example
+ \ingroup webengine-widgetexamples
+ \brief A simple browser based on Qt WebEngine Widgets
+
+ \image simplebrowser.png
+
+ \e {Simple Browser} demonstrates how to use the
+ \l{Qt WebEngine Widgets C++ Classes}{Qt WebEngine C++ classes} to develop a
+ small Web browser application that contains the following elements:
+
+ \list
+ \li Menu bar for opening stored pages and managing windows and tabs.
+ \li Navigation bar for entering a URL and for moving backward and
+ forward in the web page browsing history.
+ \li Multi-tab area for displaying web content within tabs.
+ \li Status bar for displaying hovered links.
+ \endlist
+
+ The web content can be opened in new tabs or separate windows. HTTP and
+ proxy authentication can be used for accessing web pages.
+
+ \include examples-run.qdocinc
+
+ \section1 Class Hierarchy
+
+ We start with sketching a diagram of the classes that we are going to
+ implement:
+
+ \image simplebrowser-model.png
+
+ \list
+ \li \c{Browser} is a singleton class managing the application windows.
+ \li \c{BrowserWindow} is a \l QMainWindow showing the menu, a navigation
+ bar, \c {TabWidget}, and a status bar.
+ \li \c{TabWidget} is a \l QTabWidget and contains one or multiple
+ browser tabs.
+ \li \c{WebView} is a \l QWebEngineView, provides a view for \c{WebPage},
+ and is added as a tab in \c{TabWidget}.
+ \li \c{WebPage} is a \l QWebEnginePage that represents website content.
+ \endlist
+
+ \section1 Creating the Browser Main Window
+
+ This example supports multiple main windows that are owned by a
+ \c Browser singleton object. This class could also be used for further
+ functionality, such as downloading files, bookmarks, and history managers.
+
+ In \c main.cpp, we create the first \c BrowserWindow instance and add it
+ to the \c Browser object. If no arguments are passed on the command line,
+ we open the \l{Qt Homepage}:
+
+ \quotefromfile webenginewidgets/simplebrowser/main.cpp
+ \skipto main
+ \printuntil }
+
+ \section1 Creating Tabs
+
+ The \c BrowserWindow constructor initializes all the necessary user interface
+ related objects. The \c centralWidget of \c BrowserWindow contains an instance of
+ \c TabWidget. The \c TabWidget contains one or several \c WebView instances as tabs,
+ and delegates it's signals and slots to the currently selected one:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.h
+ \skipto TabWidget :
+ \printuntil {
+ \dots
+ \skipto signals
+ \printuntil triggerWebPageAction
+ \skipto }
+ \dots
+ \printline };
+
+ Each tab contains an instance of \c WebView:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto TabWidget::createTab(
+ \printuntil }
+
+ In \c TabWidget::setupView(), we make sure that the \c TabWidget always forwards
+ the signals of the currently selected \c WebView:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto TabWidget::setupView
+ \printuntil emit loadProgress
+ \skipto closeTab
+ \skipto });
+ \printline }
+ \dots
+ \printline }
+
+ \section1 Implementing WebView Functionality
+
+ The \c WebView is derived from QWebEngineView to support the following
+ functionality:
+
+ \list
+ \li Downloading favicons
+ \li Displaying error messages in case \c renderProcess dies
+ \li Handling \c createWindow requests
+ \li Adding custom menu items to context menus
+ \endlist
+
+ First, we create the WebView with the necessary methods and signals:
+
+ \quotefromfile webenginewidgets/simplebrowser/webview.h
+ \skipto WebView :
+ \printuntil WebView(
+ \dots
+ \skipto protected:
+ \printuntil handleIconLoaded
+ \skipto }
+ \dots
+ \printline };
+
+ \section2 Downloading Favicons
+
+ To download a favicon, we use QNetworkAccessManager and create a
+ QNetworkRequest every time the URL specified by
+ QWebEngineView::iconUrlChanged is emitted:
+
+ \quotefromfile webenginewidgets/simplebrowser/webview.cpp
+ \skipto WebView::handleIconUrlChanged(
+ \printuntil }
+
+ \section2 Displaying Error Messages
+
+ If the render process is terminated, we display a QMessageBox with an error
+ code, and then we reload the page:
+
+ \quotefromfile webenginewidgets/simplebrowser/webview.cpp
+ \skipto WebView::WebView(QWidget *parent)
+ \printuntil {
+ \skipto renderProcessTerminated
+ \dots
+ \printuntil QTimer
+ \printline });
+ \printline }
+
+ \section2 Managing WebWindows
+
+ The loaded page might want to create windows of the type
+ QWebEnginePage::WebWindowType, for example, when a JavaScript program
+ requests to open a document in a new window or dialog.
+ This is handled by overriding \c QWebView::createWindow():
+
+ \skipto WebView::createWindow(
+ \printuntil return nullptr;
+ \printuntil }
+
+ In case of \c QWebEnginePage::WebDialog, we create an instance of a custom \c WebPopupWindow class:
+
+ \quotefromfile webenginewidgets/simplebrowser/webpopupwindow.h
+ \skipto class WebPopupWindow
+ \printuntil };
+
+ \section2 Adding Context Menu Items
+
+ We add menu items to the context menu, so that users can right-click a link
+ to have it opened in the same tab, a new window, or a new tab. We override
+ QWebEngineView::contextMenuEvent and use
+ QWebEnginePage::createStandardContextMenu to create a default QMenu with a
+ default list of QWebEnginePage::WebAction actions.
+
+ The default name for QWebEnginePage::OpenLinkInThisWindow action is
+ \uicontrol Follow. For clarity, we rename it
+ \uicontrol {Open Link in This Tab}. Also, we add the actions for opening
+ links in a separate window or in a new tab:
+
+ \quotefromfile webenginewidgets/simplebrowser/webview.cpp
+ \skipto WebView::contextMenuEvent(
+ \printuntil menu->popup
+ \printline }
+
+ \section1 Implementing WebPage Functionality
+
+ As mentioned earlier, each \c WebView contains a \c WebPage instance that
+ was created by using QWebEngineProfile::defaultProfile().
+
+ We implement \c WebPage as a subclass of QWebEnginePage to enable HTTP,
+ proxy authentication, and ignoring SSL certificate errors when accessing web
+ pages:
+
+ \quotefromfile webenginewidgets/simplebrowser/webpage.h
+ \skipto WebPage :
+ \printuntil }
+
+ In all the cases above, we display the appropriate dialog to the user. In
+ case of authentication, we need to set the correct credential values on the
+ QAuthenticator object:
+
+ \quotefromfile webenginewidgets/simplebrowser/webpage.cpp
+ \skipto WebPage::handleAuthenticationRequired(
+ \printuntil }
+ \printuntil }
+ \printline }
+
+ The \c handleProxyAuthenticationRequired signal handler implements the very same
+ steps for the authentication of HTTP proxies.
+
+ In case of SSL errors, we just need to return a boolean value indicating
+ whether the certificate should be ignored.
+
+ \quotefromfile webenginewidgets/simplebrowser/webpage.cpp
+ \skipto WebPage::certificateError(
+ \printuntil }
+ \printuntil }
+
+ \section1 Opening a Web Page
+
+ This section describes the workflow for opening a new page.
+ When the user enters a URL in the navigation bar and presses \uicontrol Enter,
+ \c QLineEdit::returnPressed is emitted, which lets \c BrowserWindow
+ load the requested page:
+
+ \quotefromfile webenginewidgets/simplebrowser/browserwindow.cpp
+ \skipto connect(m_urlLineEdit
+ \printuntil });
+
+ The \c loadPage() method calls the \c setUrl() method of \c TabWidget:
+
+ \skipto void BrowserWindow::loadPage(const QUrl
+ \printuntil }
+ \printline }
+
+ The call is forwarded to the currently selected tab:
+
+ \quotefromfile webenginewidgets/simplebrowser/tabwidget.cpp
+ \skipto TabWidget::setUrl(
+ \printuntil }
+ \printuntil }
+
+ The \c setUrl() method of \c WebView just forwards the \c url to the associated \c WebPage,
+ which in turn starts the downloading of the page's content in the background.
+*/
diff --git a/examples/webenginewidgets/simplebrowser/main.cpp b/examples/webenginewidgets/simplebrowser/main.cpp
new file mode 100644
index 000000000..761403fb5
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/main.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "browser.h"
+#include "browserwindow.h"
+#include <QApplication>
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ app.setWindowIcon(QIcon(QLatin1String(":simplebrowser.svg")));
+
+ BrowserWindow *window = new BrowserWindow();
+ Browser::instance().addWindow(window);
+
+ QStringList args = QCoreApplication::arguments();
+ if (args.count() > 1)
+ window->loadPage(args.last());
+ else
+ window->loadHomePage();
+
+ return app.exec();
+}
diff --git a/examples/webenginewidgets/simplebrowser/passworddialog.ui b/examples/webenginewidgets/simplebrowser/passworddialog.ui
new file mode 100644
index 000000000..bbf5004f5
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/passworddialog.ui
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PasswordDialog</class>
+ <widget class="QDialog" name="PasswordDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>399</width>
+ <height>148</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Authentication Required</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout" columnstretch="0,0" columnminimumwidth="0,0">
+ <item row="0" column="0">
+ <widget class="QLabel" name="m_iconLabel">
+ <property name="text">
+ <string>Icon</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLabel" name="m_infoLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Info</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="userLabel">
+ <property name="text">
+ <string>Username:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="m_userNameLineEdit"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="passwordLabel">
+ <property name="text">
+ <string>Password:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="m_passwordLineEdit">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ <zorder>userLabel</zorder>
+ <zorder>m_userNameLineEdit</zorder>
+ <zorder>passwordLabel</zorder>
+ <zorder>m_passwordLineEdit</zorder>
+ <zorder>buttonBox</zorder>
+ <zorder>m_iconLabel</zorder>
+ <zorder>m_infoLabel</zorder>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>PasswordDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/examples/webenginewidgets/simplebrowser/simplebrowser.pro b/examples/webenginewidgets/simplebrowser/simplebrowser.pro
new file mode 100644
index 000000000..ad8a9a2bd
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/simplebrowser.pro
@@ -0,0 +1,33 @@
+TEMPLATE = app
+TARGET = simplebrowser
+QT += webenginewidgets network
+CONFIG += c++11
+
+HEADERS += \
+ browser.h \
+ browserwindow.h \
+ tabwidget.h \
+ urllineedit.h \
+ webview.h \
+ webpage.h \
+ webpopupwindow.h
+
+SOURCES += \
+ browser.cpp \
+ browserwindow.cpp \
+ main.cpp \
+ tabwidget.cpp \
+ urllineedit.cpp \
+ webview.cpp \
+ webpage.cpp \
+ webpopupwindow.cpp
+
+FORMS += \
+ certificateerrordialog.ui \
+ passworddialog.ui
+
+RESOURCES += data/simplebrowser.qrc
+
+# install
+target.path = $$[QT_INSTALL_EXAMPLES]/webenginewidgets/simplebrowser
+INSTALLS += target
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.cpp b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
new file mode 100644
index 000000000..d9e0dea1b
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "tabwidget.h"
+#include "webpage.h"
+#include "webview.h"
+#include <QMenu>
+#include <QTabBar>
+#include <QWebEngineProfile>
+
+TabWidget::TabWidget(QWidget *parent)
+ : QTabWidget(parent)
+{
+ QTabBar *tabBar = this->tabBar();
+ tabBar->setTabsClosable(true);
+ tabBar->setSelectionBehaviorOnRemove(QTabBar::SelectPreviousTab);
+ tabBar->setMovable(true);
+ tabBar->setContextMenuPolicy(Qt::CustomContextMenu);
+ connect(tabBar, &QTabBar::customContextMenuRequested, this, &TabWidget::handleContextMenuRequested);
+ connect(tabBar, &QTabBar::tabCloseRequested, this, &TabWidget::closeTab);
+ connect(tabBar, &QTabBar::tabBarDoubleClicked, [this](int index) {
+ if (index != -1)
+ return;
+ createTab();
+ });
+
+ setDocumentMode(true);
+ setElideMode(Qt::ElideRight);
+
+ connect(this, &QTabWidget::currentChanged, this, &TabWidget::handleCurrentChanged);
+}
+
+TabWidget::~TabWidget()
+{
+}
+
+void TabWidget::handleCurrentChanged(int index)
+{
+ if (index != -1) {
+ WebView *view = webView(index);
+ if (!view->url().isEmpty())
+ view->setFocus();
+ emit titleChanged(view->title());
+ emit loadProgress(view->loadProgress());
+ emit urlChanged(view->url());
+ emit iconChanged(view->icon());
+ emit webActionEnabledChanged(QWebEnginePage::Back, view->isWebActionEnabled(QWebEnginePage::Back));
+ emit webActionEnabledChanged(QWebEnginePage::Forward, view->isWebActionEnabled(QWebEnginePage::Forward));
+ emit webActionEnabledChanged(QWebEnginePage::Stop, view->isWebActionEnabled(QWebEnginePage::Stop));
+ emit webActionEnabledChanged(QWebEnginePage::Reload,view->isWebActionEnabled(QWebEnginePage::Reload));
+ } else {
+ emit titleChanged(QString());
+ emit loadProgress(0);
+ emit urlChanged(QUrl());
+ emit iconChanged(QIcon());
+ emit webActionEnabledChanged(QWebEnginePage::Back, false);
+ emit webActionEnabledChanged(QWebEnginePage::Forward, false);
+ emit webActionEnabledChanged(QWebEnginePage::Stop, false);
+ emit webActionEnabledChanged(QWebEnginePage::Reload, true);
+ }
+}
+
+void TabWidget::handleContextMenuRequested(const QPoint &pos)
+{
+ QMenu menu;
+ menu.addAction(tr("New &Tab"), this, &TabWidget::createTab, QKeySequence::AddTab);
+ int index = tabBar()->tabAt(pos);
+ if (index != -1) {
+ QAction *action = menu.addAction(tr("Clone Tab"));
+ connect(action, &QAction::triggered, this, [this,index]() {
+ cloneTab(index);
+ });
+ menu.addSeparator();
+ action = menu.addAction(tr("&Close Tab"));
+ action->setShortcut(QKeySequence::Close);
+ connect(action, &QAction::triggered, this, [this,index]() {
+ closeTab(index);
+ });
+ action = menu.addAction(tr("Close &Other Tabs"));
+ connect(action, &QAction::triggered, this, [this,index]() {
+ closeOtherTabs(index);
+ });
+ menu.addSeparator();
+ action = menu.addAction(tr("Reload Tab"));
+ action->setShortcut(QKeySequence::Refresh);
+ connect(action, &QAction::triggered, this, [this,index]() {
+ reloadTab(index);
+ });
+ } else {
+ menu.addSeparator();
+ }
+ menu.addAction(tr("Reload All Tabs"), this, &TabWidget::reloadAllTabs);
+ menu.exec(QCursor::pos());
+}
+
+WebView *TabWidget::currentWebView() const
+{
+ return webView(currentIndex());
+}
+
+WebView *TabWidget::webView(int index) const
+{
+ return qobject_cast<WebView*>(widget(index));
+}
+
+void TabWidget::setupView(WebView *webView)
+{
+ QWebEnginePage *webPage = webView->page();
+
+ connect(webView, &QWebEngineView::titleChanged, [this, webView](const QString &title) {
+ int index = indexOf(webView);
+ if (index != -1)
+ setTabText(index, title);
+ if (currentIndex() == index)
+ emit titleChanged(title);
+ });
+ connect(webView, &QWebEngineView::urlChanged, [this, webView](const QUrl &url) {
+ int index = indexOf(webView);
+ if (index != -1)
+ tabBar()->setTabData(index, url);
+ if (currentIndex() == index)
+ emit urlChanged(url);
+ });
+ connect(webView, &QWebEngineView::loadProgress, [this, webView](int progress) {
+ if (currentIndex() == indexOf(webView))
+ emit loadProgress(progress);
+ });
+ connect(webPage, &QWebEnginePage::linkHovered, [this, webView](const QString &url) {
+ if (currentIndex() == indexOf(webView))
+ emit linkHovered(url);
+ });
+ connect(webView, &WebView::iconChanged, [this, webView](const QIcon& icon) {
+ int index = indexOf(webView);
+ if (index != -1)
+ setTabIcon(index, icon);
+ if (currentIndex() == index)
+ emit iconChanged(icon);
+ });
+ connect(webView, &WebView::webActionEnabledChanged, [this, webView](QWebEnginePage::WebAction action, bool enabled) {
+ if (currentIndex() == indexOf(webView))
+ emit webActionEnabledChanged(action,enabled);
+ });
+ connect(webView, &QWebEngineView::loadStarted, [this, webView]() {
+ int index = indexOf(webView);
+ if (index != -1) {
+ QIcon icon(QLatin1String(":loading.gif"));
+ setTabIcon(index, icon);
+ }
+ });
+ connect(webPage, &QWebEnginePage::windowCloseRequested, [this, webView]() {
+ int index = indexOf(webView);
+ if (index >= 0)
+ closeTab(index);
+ });
+}
+
+WebView *TabWidget::createTab(bool makeCurrent)
+{
+ WebView *webView = new WebView;
+ WebPage *webPage = new WebPage(QWebEngineProfile::defaultProfile(), webView);
+ webView->setPage(webPage);
+ setupView(webView);
+ addTab(webView, tr("(Untitled)"));
+ if (makeCurrent)
+ setCurrentWidget(webView);
+ return webView;
+}
+
+void TabWidget::reloadAllTabs()
+{
+ for (int i = 0; i < count(); ++i)
+ webView(i)->reload();
+}
+
+void TabWidget::closeOtherTabs(int index)
+{
+ for (int i = count() - 1; i > index; --i)
+ closeTab(i);
+ for (int i = index - 1; i >= 0; --i)
+ closeTab(i);
+}
+
+void TabWidget::closeTab(int index)
+{
+ if (WebView *view = webView(index)) {
+ bool hasFocus = view->hasFocus();
+ removeTab(index);
+ if (hasFocus && count() > 0)
+ currentWebView()->setFocus();
+ if (count() == 0)
+ createTab();
+ view->deleteLater();
+ }
+}
+
+void TabWidget::cloneTab(int index)
+{
+ if (WebView *view = webView(index)) {
+ WebView *tab = createTab(false);
+ tab->setUrl(view->url());
+ }
+}
+
+void TabWidget::setUrl(const QUrl &url)
+{
+ if (WebView *view = currentWebView()) {
+ view->setUrl(url);
+ view->setFocus();
+ }
+}
+
+void TabWidget::triggerWebPageAction(QWebEnginePage::WebAction action)
+{
+ if (WebView *webView = currentWebView()) {
+ webView->triggerPageAction(action);
+ webView->setFocus();
+ }
+}
+
+void TabWidget::nextTab()
+{
+ int next = currentIndex() + 1;
+ if (next == count())
+ next = 0;
+ setCurrentIndex(next);
+}
+
+void TabWidget::previousTab()
+{
+ int next = currentIndex() - 1;
+ if (next < 0)
+ next = count() - 1;
+ setCurrentIndex(next);
+}
+
+void TabWidget::reloadTab(int index)
+{
+ if (WebView *view = webView(index))
+ view->reload();
+}
diff --git a/examples/webenginewidgets/simplebrowser/tabwidget.h b/examples/webenginewidgets/simplebrowser/tabwidget.h
new file mode 100644
index 000000000..830effa4e
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/tabwidget.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef TABWIDGET_H
+#define TABWIDGET_H
+
+#include <QTabWidget>
+#include <QWebEnginePage>
+
+QT_BEGIN_NAMESPACE
+class QUrl;
+QT_END_NAMESPACE
+
+class WebView;
+
+class TabWidget : public QTabWidget
+{
+ Q_OBJECT
+
+public:
+ TabWidget(QWidget *parent = nullptr);
+ ~TabWidget();
+
+ WebView *currentWebView() const;
+
+signals:
+ // current tab/page signals
+ void linkHovered(const QString &link);
+ void loadProgress(int progress);
+ void titleChanged(const QString &title);
+ void urlChanged(const QUrl &url);
+ void iconChanged(const QIcon &icon);
+ void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
+
+public slots:
+ // current tab/page slots
+ void setUrl(const QUrl &url);
+ void triggerWebPageAction(QWebEnginePage::WebAction action);
+
+ WebView *createTab(bool makeCurrent = true);
+ void closeTab(int index);
+ void nextTab();
+ void previousTab();
+
+private slots:
+ void handleCurrentChanged(int index);
+ void handleContextMenuRequested(const QPoint &pos);
+ void cloneTab(int index);
+ void closeOtherTabs(int index);
+ void reloadAllTabs();
+ void reloadTab(int index);
+
+private:
+ WebView *webView(int index) const;
+ void setupView(WebView *webView);
+};
+
+#endif // TABWIDGET_H
diff --git a/examples/webenginewidgets/simplebrowser/urllineedit.cpp b/examples/webenginewidgets/simplebrowser/urllineedit.cpp
new file mode 100644
index 000000000..7e67b635a
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/urllineedit.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "urllineedit.h"
+#include <QToolButton>
+#include <QUrl>
+
+UrlLineEdit::UrlLineEdit(QWidget *parent)
+ : QLineEdit(parent)
+ , m_favButton(new QToolButton(this))
+ , m_clearButton(new QToolButton(this))
+{
+ m_clearButton->setIcon(QIcon(QStringLiteral(":closetab.png")));
+ m_clearButton->setVisible(false);
+ m_clearButton->setCursor(Qt::ArrowCursor);
+ QString style(QStringLiteral("QToolButton { border: none; padding: 1px; }"));
+ m_clearButton->setStyleSheet(style);
+ m_favButton->setStyleSheet(style);
+ setStyleSheet(QStringLiteral("QLineEdit { padding-left: %1px; padding-right: %2px; } ")
+ .arg(m_clearButton->sizeHint().width())
+ .arg(m_favButton->sizeHint().width()));
+ int minIconHeight = qMax(m_favButton->sizeHint().height(), m_clearButton->sizeHint().height());
+ setMinimumSize(minimumSizeHint().width() +
+ m_favButton->sizeHint().width() +
+ m_clearButton->sizeHint().width(),
+ qMax(minimumSizeHint().height(), minIconHeight));
+
+ connect(m_clearButton, &QToolButton::clicked, this, &QLineEdit::clear);
+ connect(this, &QLineEdit::textChanged, [this](const QString &text) {
+ m_clearButton->setVisible(!text.isEmpty() && !isReadOnly());
+ });
+}
+
+QUrl UrlLineEdit::url() const
+{
+ return QUrl::fromUserInput(text());
+}
+
+void UrlLineEdit::setUrl(const QUrl &url)
+{
+ setText(url.toString());
+ setCursorPosition(0);
+}
+
+void UrlLineEdit::setFavIcon(const QIcon &icon)
+{
+ QPixmap pixmap = icon.pixmap(16, 16);
+ m_favButton->setIcon(pixmap);
+}
+
+void UrlLineEdit::resizeEvent(QResizeEvent *event)
+{
+ QLineEdit::resizeEvent(event);
+ QSize clearButtonSize = m_clearButton->sizeHint();
+ m_clearButton->move(rect().right() - clearButtonSize.width(),
+ (rect().bottom() - clearButtonSize.height()) / 2);
+ m_favButton->move(rect().left(), (rect().bottom() - m_favButton->sizeHint().height()) / 2);
+}
diff --git a/examples/webenginewidgets/simplebrowser/urllineedit.h b/examples/webenginewidgets/simplebrowser/urllineedit.h
new file mode 100644
index 000000000..a01eb0e66
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/urllineedit.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef URLLINEEDIT_H
+#define URLLINEEDIT_H
+
+#include <QLineEdit>
+
+QT_BEGIN_NAMESPACE
+class QToolButton;
+QT_END_NAMESPACE
+
+class UrlLineEdit : public QLineEdit
+{
+ Q_OBJECT
+
+public:
+ UrlLineEdit(QWidget *parent = nullptr);
+
+public:
+ QUrl url() const;
+ void setUrl(const QUrl &url);
+ void setFavIcon(const QIcon &icon);
+
+protected:
+ void resizeEvent(QResizeEvent *event) override;
+
+private:
+ QToolButton *m_favButton;
+ QToolButton *m_clearButton;
+};
+
+#endif // URLLINEEDIT_H
diff --git a/examples/webenginewidgets/simplebrowser/webpage.cpp b/examples/webenginewidgets/simplebrowser/webpage.cpp
new file mode 100644
index 000000000..ae0ef3f48
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webpage.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "browserwindow.h"
+#include "tabwidget.h"
+#include "ui_certificateerrordialog.h"
+#include "ui_passworddialog.h"
+#include "webpage.h"
+#include "webview.h"
+#include <QAuthenticator>
+#include <QMessageBox>
+
+WebPage::WebPage(QWebEngineProfile *profile, QObject *parent)
+ : QWebEnginePage(profile, parent)
+{
+ connect(this, &QWebEnginePage::authenticationRequired, this, &WebPage::handleAuthenticationRequired);
+ connect(this, &QWebEnginePage::proxyAuthenticationRequired, this, &WebPage::handleProxyAuthenticationRequired);
+}
+
+bool WebPage::certificateError(const QWebEngineCertificateError &error)
+{
+ QWidget *mainWindow = view()->window();
+ if (error.isOverridable()) {
+ QDialog dialog(mainWindow);
+ dialog.setModal(true);
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ Ui::CertificateErrorDialog certificateDialog;
+ certificateDialog.setupUi(&dialog);
+ certificateDialog.m_iconLabel->setText(QString());
+ QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, mainWindow));
+ certificateDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
+ certificateDialog.m_errorLabel->setText(error.errorDescription());
+ dialog.setWindowTitle(tr("Certificate Error"));
+ return dialog.exec() == QDialog::Accepted;
+ }
+
+ QMessageBox::critical(mainWindow, tr("Certificate Error"), error.errorDescription());
+ return false;
+}
+
+void WebPage::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth)
+{
+ QWidget *mainWindow = view()->window();
+ QDialog dialog(mainWindow);
+ dialog.setModal(true);
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ Ui::PasswordDialog passwordDialog;
+ passwordDialog.setupUi(&dialog);
+
+ passwordDialog.m_iconLabel->setText(QString());
+ QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow));
+ passwordDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
+
+ QString introMessage(tr("Enter username and password for \"%1\" at %2")
+ .arg(auth->realm()).arg(requestUrl.toString().toHtmlEscaped()));
+ passwordDialog.m_infoLabel->setText(introMessage);
+ passwordDialog.m_infoLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(passwordDialog.m_userNameLineEdit->text());
+ auth->setPassword(passwordDialog.m_passwordLineEdit->text());
+ } else {
+ // Set authenticator null if dialog is cancelled
+ *auth = QAuthenticator();
+ }
+}
+
+void WebPage::handleProxyAuthenticationRequired(const QUrl &, QAuthenticator *auth, const QString &proxyHost)
+{
+ QWidget *mainWindow = view()->window();
+ QDialog dialog(mainWindow);
+ dialog.setModal(true);
+ dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);
+
+ Ui::PasswordDialog passwordDialog;
+ passwordDialog.setupUi(&dialog);
+
+ passwordDialog.m_iconLabel->setText(QString());
+ QIcon icon(mainWindow->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, mainWindow));
+ passwordDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));
+
+ QString introMessage = tr("Connect to proxy \"%1\" using:");
+ introMessage = introMessage.arg(proxyHost.toHtmlEscaped());
+ passwordDialog.m_infoLabel->setText(introMessage);
+ passwordDialog.m_infoLabel->setWordWrap(true);
+
+ if (dialog.exec() == QDialog::Accepted) {
+ auth->setUser(passwordDialog.m_userNameLineEdit->text());
+ auth->setPassword(passwordDialog.m_passwordLineEdit->text());
+ } else {
+ // Set authenticator null if dialog is cancelled
+ *auth = QAuthenticator();
+ }
+}
diff --git a/examples/webenginewidgets/simplebrowser/webpage.h b/examples/webenginewidgets/simplebrowser/webpage.h
new file mode 100644
index 000000000..521534b50
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webpage.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef WEBPAGE_H
+#define WEBPAGE_H
+
+#include <QWebEnginePage>
+
+class WebPage : public QWebEnginePage
+{
+ Q_OBJECT
+
+public:
+ WebPage(QWebEngineProfile *profile, QObject *parent = nullptr);
+
+protected:
+ bool certificateError(const QWebEngineCertificateError &error) override;
+
+private slots:
+ void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
+ void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth, const QString &proxyHost);
+};
+
+#endif // WEBPAGE_H
diff --git a/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp b/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp
new file mode 100644
index 000000000..a3175e546
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webpopupwindow.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "urllineedit.h"
+#include "webpage.h"
+#include "webpopupwindow.h"
+#include "webview.h"
+#include <QIcon>
+#include <QVBoxLayout>
+
+WebPopupWindow::WebPopupWindow(QWebEngineProfile *profile)
+ : m_addressBar(new UrlLineEdit(this))
+ , m_view(new WebView(this))
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->setMargin(0);
+ setLayout(layout);
+ layout->addWidget(m_addressBar);
+ layout->addWidget(m_view);
+
+ m_view->setPage(new WebPage(profile, m_view));
+ m_view->setFocus();
+ m_addressBar->setReadOnly(true);
+ m_addressBar->setFavIcon(QIcon(QStringLiteral(":defaulticon.png")));
+
+ connect(m_view, &WebView::titleChanged, this, &QWidget::setWindowTitle);
+ connect(m_view, &WebView::urlChanged, this, &WebPopupWindow::setUrl);
+ connect(m_view, &WebView::iconChanged, this, &WebPopupWindow::handleIconChanged);
+ connect(m_view->page(), &WebPage::geometryChangeRequested, this, &WebPopupWindow::handleGeometryChangeRequested);
+ connect(m_view->page(), &WebPage::windowCloseRequested, this, &QWidget::close);
+}
+
+QWebEngineView *WebPopupWindow::view() const
+{
+ return m_view;
+}
+
+void WebPopupWindow::setUrl(const QUrl &url)
+{
+ m_addressBar->setUrl(url);
+}
+
+void WebPopupWindow::handleGeometryChangeRequested(const QRect &newGeometry)
+{
+ m_view->setMinimumSize(newGeometry.width(), newGeometry.height());
+ move(newGeometry.topLeft() - m_view->pos());
+ // let the layout do the magic
+ resize(0, 0);
+ show();
+}
+
+void WebPopupWindow::handleIconChanged(const QIcon &icon)
+{
+ m_addressBar->setFavIcon(icon);
+}
diff --git a/examples/webenginewidgets/simplebrowser/webpopupwindow.h b/examples/webenginewidgets/simplebrowser/webpopupwindow.h
new file mode 100644
index 000000000..af97ef7fc
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webpopupwindow.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef WEBPOPUPWINDOW_H
+#define WEBPOPUPWINDOW_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QWebEngineProfile;
+class QWebEngineView;
+QT_END_NAMESPACE
+
+class WebView;
+class UrlLineEdit;
+
+class WebPopupWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ WebPopupWindow(QWebEngineProfile *profile);
+ QWebEngineView *view() const;
+ void setUrl(const QUrl &url);
+
+private slots:
+ void handleGeometryChangeRequested(const QRect &newGeometry);
+ void handleIconChanged(const QIcon &icon);
+
+private:
+ UrlLineEdit *m_addressBar;
+ WebView *m_view;
+};
+#endif // WEBPOPUPWINDOW_H
diff --git a/examples/webenginewidgets/simplebrowser/webview.cpp b/examples/webenginewidgets/simplebrowser/webview.cpp
new file mode 100644
index 000000000..1fabcc69f
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webview.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 "browser.h"
+#include "browserwindow.h"
+#include "tabwidget.h"
+#include "webpage.h"
+#include "webpopupwindow.h"
+#include "webview.h"
+#include <QContextMenuEvent>
+#include <QMenu>
+#include <QMessageBox>
+#include <QNetworkReply>
+#include <QTimer>
+
+WebView::WebView(QWidget *parent)
+ : QWebEngineView(parent)
+ , m_loadProgress(0)
+{
+ connect(this, &QWebEngineView::loadProgress, [this](int progress) {
+ m_loadProgress = progress;
+ });
+ connect(this, &QWebEngineView::loadFinished, [this](bool success) {
+ if (!success) {
+ qWarning() << "Could not load page: " << url();
+ m_loadProgress = 0;
+ }
+ });
+ connect(this, &QWebEngineView::iconUrlChanged, this, &WebView::handleIconUrlChanged);
+ connect(this, &QWebEngineView::renderProcessTerminated,
+ [this](QWebEnginePage::RenderProcessTerminationStatus termStatus, int statusCode) {
+ QString status;
+ switch (termStatus) {
+ case QWebEnginePage::NormalTerminationStatus:
+ status = tr("Render process normal exit");
+ break;
+ case QWebEnginePage::AbnormalTerminationStatus:
+ status = tr("Render process abnormal exit");
+ break;
+ case QWebEnginePage::CrashedTerminationStatus:
+ status = tr("Render process crashed");
+ break;
+ case QWebEnginePage::KilledTerminationStatus:
+ status = tr("Render process killed");
+ break;
+ }
+ QMessageBox::critical(window(), status, tr("Render process exited with code: %1").arg(statusCode));
+ QTimer::singleShot(0, [this] { reload(); });
+ });
+}
+
+void WebView::setPage(WebPage *page)
+{
+ createWebActionTrigger(page,QWebEnginePage::Forward);
+ createWebActionTrigger(page,QWebEnginePage::Back);
+ createWebActionTrigger(page,QWebEnginePage::Reload);
+ createWebActionTrigger(page,QWebEnginePage::Stop);
+ QWebEngineView::setPage(page);
+}
+
+QIcon WebView::icon() const
+{
+ if (!m_icon.isNull())
+ return m_icon;
+ return QIcon(QLatin1String(":defaulticon.png"));
+}
+
+int WebView::loadProgress() const
+{
+ return m_loadProgress;
+}
+
+void WebView::createWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction webAction)
+{
+ QAction *action = page->action(webAction);
+ connect(action, &QAction::changed, [this, action, webAction]{
+ emit webActionEnabledChanged(webAction, action->isEnabled());
+ });
+}
+
+bool WebView::isWebActionEnabled(QWebEnginePage::WebAction webAction) const
+{
+ return page()->action(webAction)->isEnabled();
+}
+
+QNetworkAccessManager &WebView::networkAccessManager()
+{
+ static QNetworkAccessManager networkAccessManager;
+ return networkAccessManager;
+}
+
+QWebEngineView *WebView::createWindow(QWebEnginePage::WebWindowType type)
+{
+ switch (type) {
+ case QWebEnginePage::WebBrowserTab: {
+ BrowserWindow *mainWindow = qobject_cast<BrowserWindow*>(window());
+ return mainWindow->tabWidget()->createTab();
+ }
+ case QWebEnginePage::WebBrowserWindow: {
+ BrowserWindow *mainWindow = new BrowserWindow();
+ Browser::instance().addWindow(mainWindow);
+ return mainWindow->currentTab();
+ }
+ case QWebEnginePage::WebDialog: {
+ WebPopupWindow *popup = new WebPopupWindow(page()->profile());
+ return popup->view();
+ }
+ }
+ return nullptr;
+}
+
+void WebView::contextMenuEvent(QContextMenuEvent *event)
+{
+ QMenu *menu = page()->createStandardContextMenu();
+ const QList<QAction*> actions = menu->actions();
+ auto it = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::OpenLinkInThisWindow));
+ if (it != actions.cend()) {
+ (*it)->setText(tr("Open Link in This Tab"));
+ ++it;
+ menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewWindow));
+ menu->insertAction(*it, page()->action(QWebEnginePage::OpenLinkInNewTab));
+ }
+ menu->popup(event->globalPos());
+}
+
+void WebView::handleIconUrlChanged(const QUrl &url)
+{
+ QNetworkRequest iconRequest(url);
+#ifndef QT_NO_OPENSSL
+ QSslConfiguration conf = iconRequest.sslConfiguration();
+ conf.setPeerVerifyMode(QSslSocket::VerifyNone);
+ iconRequest.setSslConfiguration(conf);
+#endif
+ QNetworkReply *iconReply = networkAccessManager().get(iconRequest);
+ iconReply->setParent(this);
+ connect(iconReply, &QNetworkReply::finished, this, &WebView::handleIconLoaded);
+}
+
+void WebView::handleIconLoaded()
+{
+ QNetworkReply *iconReply = qobject_cast<QNetworkReply*>(sender());
+ if (iconReply && iconReply->error() == QNetworkReply::NoError) {
+ QByteArray data = iconReply->readAll();
+ QPixmap pixmap;
+ pixmap.loadFromData(data);
+ m_icon.addPixmap(pixmap);
+ iconReply->deleteLater();
+ } else {
+ m_icon = QIcon(QStringLiteral(":defaulticon.png"));
+ }
+ emit iconChanged(m_icon);
+}
diff --git a/examples/webenginewidgets/simplebrowser/webview.h b/examples/webenginewidgets/simplebrowser/webview.h
new file mode 100644
index 000000000..5450ee247
--- /dev/null
+++ b/examples/webenginewidgets/simplebrowser/webview.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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$
+**
+****************************************************************************/
+
+#ifndef WEBVIEW_H
+#define WEBVIEW_H
+
+#include <QIcon>
+#include <QWebEngineView>
+
+class WebPage;
+
+class WebView : public QWebEngineView
+{
+ Q_OBJECT
+
+public:
+ WebView(QWidget *parent = nullptr);
+ void setPage(WebPage *page);
+
+ QIcon icon() const;
+ int loadProgress() const;
+ bool isWebActionEnabled(QWebEnginePage::WebAction webAction) const;
+ static QNetworkAccessManager &networkAccessManager();
+
+protected:
+ void contextMenuEvent(QContextMenuEvent *event) override;
+ QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) override;
+
+signals:
+ void iconChanged(const QIcon &icon);
+ void webActionEnabledChanged(QWebEnginePage::WebAction webAction, bool enabled);
+
+private slots:
+ void handleIconUrlChanged(const QUrl &url);
+ void handleIconLoaded();
+
+private:
+ void createWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction);
+
+private:
+ int m_loadProgress;
+ QIcon m_icon;
+};
+
+#endif