diff options
33 files changed, 3441 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore index ab40b145a..2a74d1302 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ examples/webenginewidgets/browser/browser examples/webenginewidgets/browser/browser.app examples/webenginewidgets/contentmanipulation/contentmanipulation examples/webenginewidgets/contentmanipulation/contentmanipulation.app +examples/webenginewidgets/simplebrowser/simplebrowser tests/quicktestbrowser/quicktestbrowser tests/**/tst_* 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 Binary files differnew file mode 100644 index 000000000..20928fb40 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/addtab.png diff --git a/examples/webenginewidgets/simplebrowser/data/closetab.png b/examples/webenginewidgets/simplebrowser/data/closetab.png Binary files differnew file mode 100644 index 000000000..ab9d669ee --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/closetab.png diff --git a/examples/webenginewidgets/simplebrowser/data/defaulticon.png b/examples/webenginewidgets/simplebrowser/data/defaulticon.png Binary files differnew file mode 100644 index 000000000..01a0920c9 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/defaulticon.png diff --git a/examples/webenginewidgets/simplebrowser/data/go-next.png b/examples/webenginewidgets/simplebrowser/data/go-next.png Binary files differnew file mode 100644 index 000000000..6f3f65d33 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/go-next.png diff --git a/examples/webenginewidgets/simplebrowser/data/go-previous.png b/examples/webenginewidgets/simplebrowser/data/go-previous.png Binary files differnew file mode 100644 index 000000000..93be3d1ee --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/go-previous.png diff --git a/examples/webenginewidgets/simplebrowser/data/process-stop.png b/examples/webenginewidgets/simplebrowser/data/process-stop.png Binary files differnew file mode 100644 index 000000000..b68290bf1 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/process-stop.png 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 Binary files differnew file mode 100644 index 000000000..cab4d02c7 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/data/view-refresh.png diff --git a/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png Binary files differnew file mode 100644 index 000000000..2a1abce50 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser-model.png diff --git a/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png Binary files differnew file mode 100644 index 000000000..777309075 --- /dev/null +++ b/examples/webenginewidgets/simplebrowser/doc/images/simplebrowser.png 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 |