1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the examples of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** BSD License Usage
18 ** Alternatively, you may use this file under the terms of the BSD license
19 ** as follows:
20 **
21 ** "Redistribution and use in source and binary forms, with or without
22 ** modification, are permitted provided that the following conditions are
23 ** met:
24 **   * Redistributions of source code must retain the above copyright
25 **     notice, this list of conditions and the following disclaimer.
26 **   * Redistributions in binary form must reproduce the above copyright
27 **     notice, this list of conditions and the following disclaimer in
28 **     the documentation and/or other materials provided with the
29 **     distribution.
30 **   * Neither the name of The Qt Company Ltd nor the names of its
31 **     contributors may be used to endorse or promote products derived
32 **     from this software without specific prior written permission.
33 **
34 **
35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46 **
47 ** $QT_END_LICENSE$
48 **
49 ****************************************************************************/
50 
51 #include "browser.h"
52 #include "browserwindow.h"
53 #include "downloadmanagerwidget.h"
54 #include "tabwidget.h"
55 #include "webview.h"
56 #include <QApplication>
57 #include <QCloseEvent>
58 #include <QDesktopWidget>
59 #include <QEvent>
60 #include <QFileDialog>
61 #include <QInputDialog>
62 #include <QMenuBar>
63 #include <QMessageBox>
64 #include <QProgressBar>
65 #include <QScreen>
66 #include <QStatusBar>
67 #include <QToolBar>
68 #include <QVBoxLayout>
69 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
70 #include <QWebEngineFindTextResult>
71 #endif
72 #include <QWebEngineProfile>
73 
BrowserWindow(Browser * browser,QWebEngineProfile * profile,bool forDevTools)74 BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools)
75     : m_browser(browser)
76     , m_profile(profile)
77     , m_tabWidget(new TabWidget(profile, this))
78     , m_progressBar(nullptr)
79     , m_historyBackAction(nullptr)
80     , m_historyForwardAction(nullptr)
81     , m_stopAction(nullptr)
82     , m_reloadAction(nullptr)
83     , m_stopReloadAction(nullptr)
84     , m_urlLineEdit(nullptr)
85     , m_favAction(nullptr)
86 {
87     setAttribute(Qt::WA_DeleteOnClose, true);
88     setFocusPolicy(Qt::ClickFocus);
89 
90     if (!forDevTools) {
91         m_progressBar = new QProgressBar(this);
92 
93         QToolBar *toolbar = createToolBar();
94         addToolBar(toolbar);
95         menuBar()->addMenu(createFileMenu(m_tabWidget));
96         menuBar()->addMenu(createEditMenu());
97         menuBar()->addMenu(createViewMenu(toolbar));
98         menuBar()->addMenu(createWindowMenu(m_tabWidget));
99         menuBar()->addMenu(createHelpMenu());
100     }
101 
102     QWidget *centralWidget = new QWidget(this);
103     QVBoxLayout *layout = new QVBoxLayout;
104     layout->setSpacing(0);
105     layout->setContentsMargins(0, 0, 0, 0);
106     if (!forDevTools) {
107         addToolBarBreak();
108 
109         m_progressBar->setMaximumHeight(1);
110         m_progressBar->setTextVisible(false);
111         m_progressBar->setStyleSheet(QStringLiteral("QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}"));
112 
113         layout->addWidget(m_progressBar);
114     }
115 
116     layout->addWidget(m_tabWidget);
117     centralWidget->setLayout(layout);
118     setCentralWidget(centralWidget);
119 
120     connect(m_tabWidget, &TabWidget::titleChanged, this, &BrowserWindow::handleWebViewTitleChanged);
121     if (!forDevTools) {
122         connect(m_tabWidget, &TabWidget::linkHovered, [this](const QString& url) {
123             statusBar()->showMessage(url);
124         });
125         connect(m_tabWidget, &TabWidget::loadProgress, this, &BrowserWindow::handleWebViewLoadProgress);
126         connect(m_tabWidget, &TabWidget::webActionEnabledChanged, this, &BrowserWindow::handleWebActionEnabledChanged);
127         connect(m_tabWidget, &TabWidget::urlChanged, [this](const QUrl &url) {
128             m_urlLineEdit->setText(url.toDisplayString());
129         });
130         connect(m_tabWidget, &TabWidget::favIconChanged, m_favAction, &QAction::setIcon);
131         connect(m_tabWidget, &TabWidget::devToolsRequested, this, &BrowserWindow::handleDevToolsRequested);
132         connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() {
133             m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text()));
134         });
135 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
136         connect(m_tabWidget, &TabWidget::findTextFinished, this, &BrowserWindow::handleFindTextFinished);
137 #endif
138 
139         QAction *focusUrlLineEditAction = new QAction(this);
140         addAction(focusUrlLineEditAction);
141         focusUrlLineEditAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L));
142         connect(focusUrlLineEditAction, &QAction::triggered, this, [this] () {
143             m_urlLineEdit->setFocus(Qt::ShortcutFocusReason);
144         });
145     }
146 
147     handleWebViewTitleChanged(QString());
148     m_tabWidget->createTab();
149 }
150 
sizeHint() const151 QSize BrowserWindow::sizeHint() const
152 {
153     QRect desktopRect = QApplication::primaryScreen()->geometry();
154     QSize size = desktopRect.size() * qreal(0.9);
155     return size;
156 }
157 
createFileMenu(TabWidget * tabWidget)158 QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget)
159 {
160     QMenu *fileMenu = new QMenu(tr("&File"));
161     fileMenu->addAction(tr("&New Window"), this, &BrowserWindow::handleNewWindowTriggered, QKeySequence::New);
162     fileMenu->addAction(tr("New &Incognito Window"), this, &BrowserWindow::handleNewIncognitoWindowTriggered);
163 
164     QAction *newTabAction = new QAction(tr("New &Tab"), this);
165     newTabAction->setShortcuts(QKeySequence::AddTab);
166     connect(newTabAction, &QAction::triggered, this, [this]() {
167         m_tabWidget->createTab();
168         m_urlLineEdit->setFocus();
169     });
170     fileMenu->addAction(newTabAction);
171 
172     fileMenu->addAction(tr("&Open File..."), this, &BrowserWindow::handleFileOpenTriggered, QKeySequence::Open);
173     fileMenu->addSeparator();
174 
175     QAction *closeTabAction = new QAction(tr("&Close Tab"), this);
176     closeTabAction->setShortcuts(QKeySequence::Close);
177     connect(closeTabAction, &QAction::triggered, [tabWidget]() {
178         tabWidget->closeTab(tabWidget->currentIndex());
179     });
180     fileMenu->addAction(closeTabAction);
181 
182     QAction *closeAction = new QAction(tr("&Quit"),this);
183     closeAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
184     connect(closeAction, &QAction::triggered, this, &QWidget::close);
185     fileMenu->addAction(closeAction);
186 
187     connect(fileMenu, &QMenu::aboutToShow, [this, closeAction]() {
188         if (m_browser->windows().count() == 1)
189             closeAction->setText(tr("&Quit"));
190         else
191             closeAction->setText(tr("&Close Window"));
192     });
193     return fileMenu;
194 }
195 
createEditMenu()196 QMenu *BrowserWindow::createEditMenu()
197 {
198     QMenu *editMenu = new QMenu(tr("&Edit"));
199     QAction *findAction = editMenu->addAction(tr("&Find"));
200     findAction->setShortcuts(QKeySequence::Find);
201     connect(findAction, &QAction::triggered, this, &BrowserWindow::handleFindActionTriggered);
202 
203     QAction *findNextAction = editMenu->addAction(tr("Find &Next"));
204     findNextAction->setShortcut(QKeySequence::FindNext);
205     connect(findNextAction, &QAction::triggered, [this]() {
206         if (!currentTab() || m_lastSearch.isEmpty())
207             return;
208         currentTab()->findText(m_lastSearch);
209     });
210 
211     QAction *findPreviousAction = editMenu->addAction(tr("Find &Previous"));
212     findPreviousAction->setShortcut(QKeySequence::FindPrevious);
213     connect(findPreviousAction, &QAction::triggered, [this]() {
214         if (!currentTab() || m_lastSearch.isEmpty())
215             return;
216         currentTab()->findText(m_lastSearch, QWebEnginePage::FindBackward);
217     });
218 
219     return editMenu;
220 }
221 
createViewMenu(QToolBar * toolbar)222 QMenu *BrowserWindow::createViewMenu(QToolBar *toolbar)
223 {
224     QMenu *viewMenu = new QMenu(tr("&View"));
225     m_stopAction = viewMenu->addAction(tr("&Stop"));
226     QList<QKeySequence> shortcuts;
227     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Period));
228     shortcuts.append(Qt::Key_Escape);
229     m_stopAction->setShortcuts(shortcuts);
230     connect(m_stopAction, &QAction::triggered, [this]() {
231         m_tabWidget->triggerWebPageAction(QWebEnginePage::Stop);
232     });
233 
234     m_reloadAction = viewMenu->addAction(tr("Reload Page"));
235     m_reloadAction->setShortcuts(QKeySequence::Refresh);
236     connect(m_reloadAction, &QAction::triggered, [this]() {
237         m_tabWidget->triggerWebPageAction(QWebEnginePage::Reload);
238     });
239 
240     QAction *zoomIn = viewMenu->addAction(tr("Zoom &In"));
241     zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
242     connect(zoomIn, &QAction::triggered, [this]() {
243         if (currentTab())
244             currentTab()->setZoomFactor(currentTab()->zoomFactor() + 0.1);
245     });
246 
247     QAction *zoomOut = viewMenu->addAction(tr("Zoom &Out"));
248     zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
249     connect(zoomOut, &QAction::triggered, [this]() {
250         if (currentTab())
251             currentTab()->setZoomFactor(currentTab()->zoomFactor() - 0.1);
252     });
253 
254     QAction *resetZoom = viewMenu->addAction(tr("Reset &Zoom"));
255     resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
256     connect(resetZoom, &QAction::triggered, [this]() {
257         if (currentTab())
258             currentTab()->setZoomFactor(1.0);
259     });
260 
261 
262     viewMenu->addSeparator();
263     QAction *viewToolbarAction = new QAction(tr("Hide Toolbar"),this);
264     viewToolbarAction->setShortcut(tr("Ctrl+|"));
265     connect(viewToolbarAction, &QAction::triggered, [toolbar,viewToolbarAction]() {
266         if (toolbar->isVisible()) {
267             viewToolbarAction->setText(tr("Show Toolbar"));
268             toolbar->close();
269         } else {
270             viewToolbarAction->setText(tr("Hide Toolbar"));
271             toolbar->show();
272         }
273     });
274     viewMenu->addAction(viewToolbarAction);
275 
276     QAction *viewStatusbarAction = new QAction(tr("Hide Status Bar"), this);
277     viewStatusbarAction->setShortcut(tr("Ctrl+/"));
278     connect(viewStatusbarAction, &QAction::triggered, [this, viewStatusbarAction]() {
279         if (statusBar()->isVisible()) {
280             viewStatusbarAction->setText(tr("Show Status Bar"));
281             statusBar()->close();
282         } else {
283             viewStatusbarAction->setText(tr("Hide Status Bar"));
284             statusBar()->show();
285         }
286     });
287     viewMenu->addAction(viewStatusbarAction);
288     return viewMenu;
289 }
290 
createWindowMenu(TabWidget * tabWidget)291 QMenu *BrowserWindow::createWindowMenu(TabWidget *tabWidget)
292 {
293     QMenu *menu = new QMenu(tr("&Window"));
294 
295     QAction *nextTabAction = new QAction(tr("Show Next Tab"), this);
296     QList<QKeySequence> shortcuts;
297     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
298     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
299     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
300     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
301     nextTabAction->setShortcuts(shortcuts);
302     connect(nextTabAction, &QAction::triggered, tabWidget, &TabWidget::nextTab);
303 
304     QAction *previousTabAction = new QAction(tr("Show Previous Tab"), this);
305     shortcuts.clear();
306     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
307     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
308     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
309     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
310     previousTabAction->setShortcuts(shortcuts);
311     connect(previousTabAction, &QAction::triggered, tabWidget, &TabWidget::previousTab);
312 
313     connect(menu, &QMenu::aboutToShow, [this, menu, nextTabAction, previousTabAction]() {
314         menu->clear();
315         menu->addAction(nextTabAction);
316         menu->addAction(previousTabAction);
317         menu->addSeparator();
318 
319         QVector<BrowserWindow*> windows = m_browser->windows();
320         int index(-1);
321         for (auto window : windows) {
322             QAction *action = menu->addAction(window->windowTitle(), this, &BrowserWindow::handleShowWindowTriggered);
323             action->setData(++index);
324             action->setCheckable(true);
325             if (window == this)
326                 action->setChecked(true);
327         }
328     });
329     return menu;
330 }
331 
createHelpMenu()332 QMenu *BrowserWindow::createHelpMenu()
333 {
334     QMenu *helpMenu = new QMenu(tr("&Help"));
335     helpMenu->addAction(tr("About &Qt"), qApp, QApplication::aboutQt);
336     return helpMenu;
337 }
338 
createToolBar()339 QToolBar *BrowserWindow::createToolBar()
340 {
341     QToolBar *navigationBar = new QToolBar(tr("Navigation"));
342     navigationBar->setMovable(false);
343     navigationBar->toggleViewAction()->setEnabled(false);
344 
345     m_historyBackAction = new QAction(this);
346     QList<QKeySequence> backShortcuts = QKeySequence::keyBindings(QKeySequence::Back);
347     for (auto it = backShortcuts.begin(); it != backShortcuts.end();) {
348         // Chromium already handles navigate on backspace when appropriate.
349         if ((*it)[0] == Qt::Key_Backspace)
350             it = backShortcuts.erase(it);
351         else
352             ++it;
353     }
354     // For some reason Qt doesn't bind the dedicated Back key to Back.
355     backShortcuts.append(QKeySequence(Qt::Key_Back));
356     m_historyBackAction->setShortcuts(backShortcuts);
357     m_historyBackAction->setIconVisibleInMenu(false);
358     m_historyBackAction->setIcon(QIcon(QStringLiteral(":go-previous.png")));
359     m_historyBackAction->setToolTip(tr("Go back in history"));
360     connect(m_historyBackAction, &QAction::triggered, [this]() {
361         m_tabWidget->triggerWebPageAction(QWebEnginePage::Back);
362     });
363     navigationBar->addAction(m_historyBackAction);
364 
365     m_historyForwardAction = new QAction(this);
366     QList<QKeySequence> fwdShortcuts = QKeySequence::keyBindings(QKeySequence::Forward);
367     for (auto it = fwdShortcuts.begin(); it != fwdShortcuts.end();) {
368         if (((*it)[0] & Qt::Key_unknown) == Qt::Key_Backspace)
369             it = fwdShortcuts.erase(it);
370         else
371             ++it;
372     }
373     fwdShortcuts.append(QKeySequence(Qt::Key_Forward));
374     m_historyForwardAction->setShortcuts(fwdShortcuts);
375     m_historyForwardAction->setIconVisibleInMenu(false);
376     m_historyForwardAction->setIcon(QIcon(QStringLiteral(":go-next.png")));
377     m_historyForwardAction->setToolTip(tr("Go forward in history"));
378     connect(m_historyForwardAction, &QAction::triggered, [this]() {
379         m_tabWidget->triggerWebPageAction(QWebEnginePage::Forward);
380     });
381     navigationBar->addAction(m_historyForwardAction);
382 
383     m_stopReloadAction = new QAction(this);
384     connect(m_stopReloadAction, &QAction::triggered, [this]() {
385         m_tabWidget->triggerWebPageAction(QWebEnginePage::WebAction(m_stopReloadAction->data().toInt()));
386     });
387     navigationBar->addAction(m_stopReloadAction);
388 
389     m_urlLineEdit = new QLineEdit(this);
390     m_favAction = new QAction(this);
391     m_urlLineEdit->addAction(m_favAction, QLineEdit::LeadingPosition);
392     m_urlLineEdit->setClearButtonEnabled(true);
393     navigationBar->addWidget(m_urlLineEdit);
394 
395     auto downloadsAction = new QAction(this);
396     downloadsAction->setIcon(QIcon(QStringLiteral(":go-bottom.png")));
397     downloadsAction->setToolTip(tr("Show downloads"));
398     navigationBar->addAction(downloadsAction);
399     connect(downloadsAction, &QAction::triggered, [this]() {
400         m_browser->downloadManagerWidget().show();
401     });
402 
403     return navigationBar;
404 }
405 
handleWebActionEnabledChanged(QWebEnginePage::WebAction action,bool enabled)406 void BrowserWindow::handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled)
407 {
408     switch (action) {
409     case QWebEnginePage::Back:
410         m_historyBackAction->setEnabled(enabled);
411         break;
412     case QWebEnginePage::Forward:
413         m_historyForwardAction->setEnabled(enabled);
414         break;
415     case QWebEnginePage::Reload:
416         m_reloadAction->setEnabled(enabled);
417         break;
418     case QWebEnginePage::Stop:
419         m_stopAction->setEnabled(enabled);
420         break;
421     default:
422         qWarning("Unhandled webActionChanged signal");
423     }
424 }
425 
handleWebViewTitleChanged(const QString & title)426 void BrowserWindow::handleWebViewTitleChanged(const QString &title)
427 {
428     QString suffix = m_profile->isOffTheRecord()
429         ? tr("Qt Simple Browser (Incognito)")
430         : tr("Qt Simple Browser");
431 
432     if (title.isEmpty())
433         setWindowTitle(suffix);
434     else
435         setWindowTitle(title + " - " + suffix);
436 }
437 
handleNewWindowTriggered()438 void BrowserWindow::handleNewWindowTriggered()
439 {
440     BrowserWindow *window = m_browser->createWindow();
441     window->m_urlLineEdit->setFocus();
442 }
443 
handleNewIncognitoWindowTriggered()444 void BrowserWindow::handleNewIncognitoWindowTriggered()
445 {
446     BrowserWindow *window = m_browser->createWindow(/* offTheRecord: */ true);
447     window->m_urlLineEdit->setFocus();
448 }
449 
handleFileOpenTriggered()450 void BrowserWindow::handleFileOpenTriggered()
451 {
452     QUrl url = QFileDialog::getOpenFileUrl(this, tr("Open Web Resource"), QString(),
453                                                 tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));
454     if (url.isEmpty())
455         return;
456     currentTab()->setUrl(url);
457 }
458 
handleFindActionTriggered()459 void BrowserWindow::handleFindActionTriggered()
460 {
461     if (!currentTab())
462         return;
463     bool ok = false;
464     QString search = QInputDialog::getText(this, tr("Find"),
465                                            tr("Find:"), QLineEdit::Normal,
466                                            m_lastSearch, &ok);
467     if (ok && !search.isEmpty()) {
468         m_lastSearch = search;
469 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
470         currentTab()->findText(m_lastSearch);
471 #else
472         currentTab()->findText(m_lastSearch, 0, [this](bool found) {
473             if (!found)
474                 statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
475         });
476 #endif
477     }
478 }
479 
closeEvent(QCloseEvent * event)480 void BrowserWindow::closeEvent(QCloseEvent *event)
481 {
482     if (m_tabWidget->count() > 1) {
483         int ret = QMessageBox::warning(this, tr("Confirm close"),
484                                        tr("Are you sure you want to close the window ?\n"
485                                           "There are %1 tabs open.").arg(m_tabWidget->count()),
486                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
487         if (ret == QMessageBox::No) {
488             event->ignore();
489             return;
490         }
491     }
492     event->accept();
493     deleteLater();
494 }
495 
tabWidget() const496 TabWidget *BrowserWindow::tabWidget() const
497 {
498     return m_tabWidget;
499 }
500 
currentTab() const501 WebView *BrowserWindow::currentTab() const
502 {
503     return m_tabWidget->currentWebView();
504 }
505 
handleWebViewLoadProgress(int progress)506 void BrowserWindow::handleWebViewLoadProgress(int progress)
507 {
508     static QIcon stopIcon(QStringLiteral(":process-stop.png"));
509     static QIcon reloadIcon(QStringLiteral(":view-refresh.png"));
510 
511     if (0 < progress && progress < 100) {
512         m_stopReloadAction->setData(QWebEnginePage::Stop);
513         m_stopReloadAction->setIcon(stopIcon);
514         m_stopReloadAction->setToolTip(tr("Stop loading the current page"));
515         m_progressBar->setValue(progress);
516     } else {
517         m_stopReloadAction->setData(QWebEnginePage::Reload);
518         m_stopReloadAction->setIcon(reloadIcon);
519         m_stopReloadAction->setToolTip(tr("Reload the current page"));
520         m_progressBar->setValue(0);
521     }
522 }
523 
handleShowWindowTriggered()524 void BrowserWindow::handleShowWindowTriggered()
525 {
526     if (QAction *action = qobject_cast<QAction*>(sender())) {
527         int offset = action->data().toInt();
528         QVector<BrowserWindow*> windows = m_browser->windows();
529         windows.at(offset)->activateWindow();
530         windows.at(offset)->currentTab()->setFocus();
531     }
532 }
533 
handleDevToolsRequested(QWebEnginePage * source)534 void BrowserWindow::handleDevToolsRequested(QWebEnginePage *source)
535 {
536     source->setDevToolsPage(m_browser->createDevToolsWindow()->currentTab()->page());
537     source->triggerAction(QWebEnginePage::InspectElement);
538 }
539 
540 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
handleFindTextFinished(const QWebEngineFindTextResult & result)541 void BrowserWindow::handleFindTextFinished(const QWebEngineFindTextResult &result)
542 {
543     if (result.numberOfMatches() == 0) {
544         statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
545     } else {
546         statusBar()->showMessage(tr("\"%1\" found: %2/%3").arg(m_lastSearch,
547                                                                QString::number(result.activeMatch()),
548                                                                QString::number(result.numberOfMatches())));
549     }
550 }
551 #endif
552