|  | /**************************************************************************** | 
|  | ** | 
|  | ** Copyright (C) 2016 The Qt Company Ltd. | 
|  | ** Contact: https://www.qt.io/licensing/ | 
|  | ** | 
|  | ** This file is part of the examples of the Qt Toolkit. | 
|  | ** | 
|  | ** $QT_BEGIN_LICENSE:BSD$ | 
|  | ** Commercial License Usage | 
|  | ** Licensees holding valid commercial Qt licenses may use this file in | 
|  | ** accordance with the commercial license agreement provided with the | 
|  | ** Software or, alternatively, in accordance with the terms contained in | 
|  | ** a written agreement between you and The Qt Company. For licensing terms | 
|  | ** and conditions see https://www.qt.io/terms-conditions. For further | 
|  | ** information use the contact form at https://www.qt.io/contact-us. | 
|  | ** | 
|  | ** BSD License Usage | 
|  | ** Alternatively, you may use this file under the terms of the BSD license | 
|  | ** as follows: | 
|  | ** | 
|  | ** "Redistribution and use in source and binary forms, with or without | 
|  | ** modification, are permitted provided that the following conditions are | 
|  | ** met: | 
|  | **   * Redistributions of source code must retain the above copyright | 
|  | **     notice, this list of conditions and the following disclaimer. | 
|  | **   * Redistributions in binary form must reproduce the above copyright | 
|  | **     notice, this list of conditions and the following disclaimer in | 
|  | **     the documentation and/or other materials provided with the | 
|  | **     distribution. | 
|  | **   * Neither the name of The Qt Company Ltd nor the names of its | 
|  | **     contributors may be used to endorse or promote products derived | 
|  | **     from this software without specific prior written permission. | 
|  | ** | 
|  | ** | 
|  | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." | 
|  | ** | 
|  | ** $QT_END_LICENSE$ | 
|  | ** | 
|  | ****************************************************************************/ | 
|  |  | 
|  | #include "browser.h" | 
|  | #include "browserwindow.h" | 
|  | #include "downloadmanagerwidget.h" | 
|  | #include "tabwidget.h" | 
|  | #include "webview.h" | 
|  | #include <QApplication> | 
|  | #include <QCloseEvent> | 
|  | #include <QDesktopWidget> | 
|  | #include <QEvent> | 
|  | #include <QFileDialog> | 
|  | #include <QInputDialog> | 
|  | #include <QMenuBar> | 
|  | #include <QMessageBox> | 
|  | #include <QProgressBar> | 
|  | #include <QScreen> | 
|  | #include <QStatusBar> | 
|  | #include <QToolBar> | 
|  | #include <QVBoxLayout> | 
|  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) | 
|  | #include <QWebEngineFindTextResult> | 
|  | #endif | 
|  | #include <QWebEngineProfile> | 
|  |  | 
|  | BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools) | 
|  | : m_browser(browser) | 
|  | , m_profile(profile) | 
|  | , m_tabWidget(new TabWidget(profile, this)) | 
|  | , m_progressBar(nullptr) | 
|  | , m_historyBackAction(nullptr) | 
|  | , m_historyForwardAction(nullptr) | 
|  | , m_stopAction(nullptr) | 
|  | , m_reloadAction(nullptr) | 
|  | , m_stopReloadAction(nullptr) | 
|  | , m_urlLineEdit(nullptr) | 
|  | , m_favAction(nullptr) | 
|  | { | 
|  | setAttribute(Qt::WA_DeleteOnClose, true); | 
|  | setFocusPolicy(Qt::ClickFocus); | 
|  |  | 
|  | if (!forDevTools) { | 
|  | m_progressBar = new QProgressBar(this); | 
|  |  | 
|  | QToolBar *toolbar = createToolBar(); | 
|  | addToolBar(toolbar); | 
|  | menuBar()->addMenu(createFileMenu(m_tabWidget)); | 
|  | menuBar()->addMenu(createEditMenu()); | 
|  | 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->setContentsMargins(0, 0, 0, 0); | 
|  | if (!forDevTools) { | 
|  | addToolBarBreak(); | 
|  |  | 
|  | m_progressBar->setMaximumHeight(1); | 
|  | m_progressBar->setTextVisible(false); | 
|  | m_progressBar->setStyleSheet(QStringLiteral("QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}")); | 
|  |  | 
|  | layout->addWidget(m_progressBar); | 
|  | } | 
|  |  | 
|  | layout->addWidget(m_tabWidget); | 
|  | centralWidget->setLayout(layout); | 
|  | setCentralWidget(centralWidget); | 
|  |  | 
|  | connect(m_tabWidget, &TabWidget::titleChanged, this, &BrowserWindow::handleWebViewTitleChanged); | 
|  | if (!forDevTools) { | 
|  | connect(m_tabWidget, &TabWidget::linkHovered, [this](const QString& url) { | 
|  | statusBar()->showMessage(url); | 
|  | }); | 
|  | connect(m_tabWidget, &TabWidget::loadProgress, this, &BrowserWindow::handleWebViewLoadProgress); | 
|  | connect(m_tabWidget, &TabWidget::webActionEnabledChanged, this, &BrowserWindow::handleWebActionEnabledChanged); | 
|  | connect(m_tabWidget, &TabWidget::urlChanged, [this](const QUrl &url) { | 
|  | m_urlLineEdit->setText(url.toDisplayString()); | 
|  | }); | 
|  | connect(m_tabWidget, &TabWidget::favIconChanged, m_favAction, &QAction::setIcon); | 
|  | connect(m_tabWidget, &TabWidget::devToolsRequested, this, &BrowserWindow::handleDevToolsRequested); | 
|  | connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() { | 
|  | m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text())); | 
|  | }); | 
|  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) | 
|  | connect(m_tabWidget, &TabWidget::findTextFinished, this, &BrowserWindow::handleFindTextFinished); | 
|  | #endif | 
|  |  | 
|  | QAction *focusUrlLineEditAction = new QAction(this); | 
|  | addAction(focusUrlLineEditAction); | 
|  | focusUrlLineEditAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L)); | 
|  | connect(focusUrlLineEditAction, &QAction::triggered, this, [this] () { | 
|  | m_urlLineEdit->setFocus(Qt::ShortcutFocusReason); | 
|  | }); | 
|  | } | 
|  |  | 
|  | handleWebViewTitleChanged(QString()); | 
|  | m_tabWidget->createTab(); | 
|  | } | 
|  |  | 
|  | QSize BrowserWindow::sizeHint() const | 
|  | { | 
|  | QRect desktopRect = QApplication::primaryScreen()->geometry(); | 
|  | 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); | 
|  | fileMenu->addAction(tr("New &Incognito Window"), this, &BrowserWindow::handleNewIncognitoWindowTriggered); | 
|  |  | 
|  | QAction *newTabAction = new QAction(tr("New &Tab"), this); | 
|  | newTabAction->setShortcuts(QKeySequence::AddTab); | 
|  | connect(newTabAction, &QAction::triggered, this, [this]() { | 
|  | m_tabWidget->createTab(); | 
|  | m_urlLineEdit->setFocus(); | 
|  | }); | 
|  | fileMenu->addAction(newTabAction); | 
|  |  | 
|  | fileMenu->addAction(tr("&Open File..."), this, &BrowserWindow::handleFileOpenTriggered, QKeySequence::Open); | 
|  | fileMenu->addSeparator(); | 
|  |  | 
|  | QAction *closeTabAction = new QAction(tr("&Close Tab"), this); | 
|  | closeTabAction->setShortcuts(QKeySequence::Close); | 
|  | 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, [this, closeAction]() { | 
|  | if (m_browser->windows().count() == 1) | 
|  | closeAction->setText(tr("&Quit")); | 
|  | else | 
|  | closeAction->setText(tr("&Close Window")); | 
|  | }); | 
|  | return fileMenu; | 
|  | } | 
|  |  | 
|  | QMenu *BrowserWindow::createEditMenu() | 
|  | { | 
|  | QMenu *editMenu = new QMenu(tr("&Edit")); | 
|  | QAction *findAction = editMenu->addAction(tr("&Find")); | 
|  | findAction->setShortcuts(QKeySequence::Find); | 
|  | connect(findAction, &QAction::triggered, this, &BrowserWindow::handleFindActionTriggered); | 
|  |  | 
|  | QAction *findNextAction = editMenu->addAction(tr("Find &Next")); | 
|  | findNextAction->setShortcut(QKeySequence::FindNext); | 
|  | connect(findNextAction, &QAction::triggered, [this]() { | 
|  | if (!currentTab() || m_lastSearch.isEmpty()) | 
|  | return; | 
|  | currentTab()->findText(m_lastSearch); | 
|  | }); | 
|  |  | 
|  | QAction *findPreviousAction = editMenu->addAction(tr("Find &Previous")); | 
|  | findPreviousAction->setShortcut(QKeySequence::FindPrevious); | 
|  | connect(findPreviousAction, &QAction::triggered, [this]() { | 
|  | if (!currentTab() || m_lastSearch.isEmpty()) | 
|  | return; | 
|  | currentTab()->findText(m_lastSearch, QWebEnginePage::FindBackward); | 
|  | }); | 
|  |  | 
|  | return editMenu; | 
|  | } | 
|  |  | 
|  | 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 = m_browser->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->setMovable(false); | 
|  | navigationBar->toggleViewAction()->setEnabled(false); | 
|  |  | 
|  | m_historyBackAction = new QAction(this); | 
|  | QList<QKeySequence> backShortcuts = QKeySequence::keyBindings(QKeySequence::Back); | 
|  | for (auto it = backShortcuts.begin(); it != backShortcuts.end();) { | 
|  | // Chromium already handles navigate on backspace when appropriate. | 
|  | if ((*it)[0] == Qt::Key_Backspace) | 
|  | it = backShortcuts.erase(it); | 
|  | else | 
|  | ++it; | 
|  | } | 
|  | // For some reason Qt doesn't bind the dedicated Back key to Back. | 
|  | backShortcuts.append(QKeySequence(Qt::Key_Back)); | 
|  | m_historyBackAction->setShortcuts(backShortcuts); | 
|  | m_historyBackAction->setIconVisibleInMenu(false); | 
|  | m_historyBackAction->setIcon(QIcon(QStringLiteral(":go-previous.png"))); | 
|  | m_historyBackAction->setToolTip(tr("Go back in history")); | 
|  | connect(m_historyBackAction, &QAction::triggered, [this]() { | 
|  | m_tabWidget->triggerWebPageAction(QWebEnginePage::Back); | 
|  | }); | 
|  | navigationBar->addAction(m_historyBackAction); | 
|  |  | 
|  | m_historyForwardAction = new QAction(this); | 
|  | QList<QKeySequence> fwdShortcuts = QKeySequence::keyBindings(QKeySequence::Forward); | 
|  | for (auto it = fwdShortcuts.begin(); it != fwdShortcuts.end();) { | 
|  | if (((*it)[0] & Qt::Key_unknown) == Qt::Key_Backspace) | 
|  | it = fwdShortcuts.erase(it); | 
|  | else | 
|  | ++it; | 
|  | } | 
|  | fwdShortcuts.append(QKeySequence(Qt::Key_Forward)); | 
|  | m_historyForwardAction->setShortcuts(fwdShortcuts); | 
|  | m_historyForwardAction->setIconVisibleInMenu(false); | 
|  | m_historyForwardAction->setIcon(QIcon(QStringLiteral(":go-next.png"))); | 
|  | m_historyForwardAction->setToolTip(tr("Go forward in history")); | 
|  | 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); | 
|  |  | 
|  | m_urlLineEdit = new QLineEdit(this); | 
|  | m_favAction = new QAction(this); | 
|  | m_urlLineEdit->addAction(m_favAction, QLineEdit::LeadingPosition); | 
|  | m_urlLineEdit->setClearButtonEnabled(true); | 
|  | navigationBar->addWidget(m_urlLineEdit); | 
|  |  | 
|  | auto downloadsAction = new QAction(this); | 
|  | downloadsAction->setIcon(QIcon(QStringLiteral(":go-bottom.png"))); | 
|  | downloadsAction->setToolTip(tr("Show downloads")); | 
|  | navigationBar->addAction(downloadsAction); | 
|  | connect(downloadsAction, &QAction::triggered, [this]() { | 
|  | m_browser->downloadManagerWidget().show(); | 
|  | }); | 
|  |  | 
|  | return navigationBar; | 
|  | } | 
|  |  | 
|  | 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 signal"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleWebViewTitleChanged(const QString &title) | 
|  | { | 
|  | QString suffix = m_profile->isOffTheRecord() | 
|  | ? tr("Qt Simple Browser (Incognito)") | 
|  | : tr("Qt Simple Browser"); | 
|  |  | 
|  | if (title.isEmpty()) | 
|  | setWindowTitle(suffix); | 
|  | else | 
|  | setWindowTitle(title + " - " + suffix); | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleNewWindowTriggered() | 
|  | { | 
|  | BrowserWindow *window = m_browser->createWindow(); | 
|  | window->m_urlLineEdit->setFocus(); | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleNewIncognitoWindowTriggered() | 
|  | { | 
|  | BrowserWindow *window = m_browser->createWindow(/* offTheRecord: */ true); | 
|  | window->m_urlLineEdit->setFocus(); | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleFileOpenTriggered() | 
|  | { | 
|  | QUrl url = QFileDialog::getOpenFileUrl(this, tr("Open Web Resource"), QString(), | 
|  | tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)")); | 
|  | if (url.isEmpty()) | 
|  | return; | 
|  | currentTab()->setUrl(url); | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleFindActionTriggered() | 
|  | { | 
|  | if (!currentTab()) | 
|  | return; | 
|  | bool ok = false; | 
|  | QString search = QInputDialog::getText(this, tr("Find"), | 
|  | tr("Find:"), QLineEdit::Normal, | 
|  | m_lastSearch, &ok); | 
|  | if (ok && !search.isEmpty()) { | 
|  | m_lastSearch = search; | 
|  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) | 
|  | currentTab()->findText(m_lastSearch); | 
|  | #else | 
|  | currentTab()->findText(m_lastSearch, 0, [this](bool found) { | 
|  | if (!found) | 
|  | statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch)); | 
|  | }); | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | 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(); | 
|  | } | 
|  |  | 
|  | 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 (0 < progress && progress < 100) { | 
|  | m_stopReloadAction->setData(QWebEnginePage::Stop); | 
|  | m_stopReloadAction->setIcon(stopIcon); | 
|  | m_stopReloadAction->setToolTip(tr("Stop loading the current page")); | 
|  | m_progressBar->setValue(progress); | 
|  | } else { | 
|  | m_stopReloadAction->setData(QWebEnginePage::Reload); | 
|  | m_stopReloadAction->setIcon(reloadIcon); | 
|  | m_stopReloadAction->setToolTip(tr("Reload the current page")); | 
|  | m_progressBar->setValue(0); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleShowWindowTriggered() | 
|  | { | 
|  | if (QAction *action = qobject_cast<QAction*>(sender())) { | 
|  | int offset = action->data().toInt(); | 
|  | QVector<BrowserWindow*> windows = m_browser->windows(); | 
|  | windows.at(offset)->activateWindow(); | 
|  | windows.at(offset)->currentTab()->setFocus(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BrowserWindow::handleDevToolsRequested(QWebEnginePage *source) | 
|  | { | 
|  | source->setDevToolsPage(m_browser->createDevToolsWindow()->currentTab()->page()); | 
|  | source->triggerAction(QWebEnginePage::InspectElement); | 
|  | } | 
|  |  | 
|  | #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) | 
|  | void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &result) | 
|  | { | 
|  | if (result.numberOfMatches() == 0) { | 
|  | statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch)); | 
|  | } else { | 
|  | statusBar()->showMessage(tr("\"%1\" found: %2/%3").arg(m_lastSearch, | 
|  | QString::number(result.activeMatch()), | 
|  | QString::number(result.numberOfMatches()))); | 
|  | } | 
|  | } | 
|  | #endif |