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