xref: /OK3568_Linux_fs/app/forlinx/flapp/src/plugins/imxwayland/simplebrowser/browserwindow.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 #include "browser.h"
2 #include "browserwindow.h"
3 #include "downloadmanagerwidget.h"
4 #include "tabwidget.h"
5 #include "webview.h"
6 #include <QApplication>
7 #include <QCloseEvent>
8 #include <QDesktopWidget>
9 #include <QEvent>
10 #include <QFileDialog>
11 #include <QInputDialog>
12 #include <QMenuBar>
13 #include <QMessageBox>
14 #include <QProgressBar>
15 #include <QStatusBar>
16 #include <QToolBar>
17 #include <QVBoxLayout>
18 #include <QWebEngineProfile>
19 
BrowserWindow(Browser * browser,QWebEngineProfile * profile)20 BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile)
21     : m_browser(browser)
22     , m_profile(profile)
23     , m_tabWidget(new TabWidget(profile, this))
24     , m_progressBar(new QProgressBar(this))
25     , m_historyBackAction(nullptr)
26     , m_historyForwardAction(nullptr)
27     , m_stopAction(nullptr)
28     , m_reloadAction(nullptr)
29     , m_stopReloadAction(nullptr)
30     , m_urlLineEdit(nullptr)
31     , m_favAction(nullptr)
32 {
33     setAttribute(Qt::WA_DeleteOnClose, true);
34     setFocusPolicy(Qt::ClickFocus);
35 
36     QToolBar *toolbar = createToolBar();
37     addToolBar(toolbar);
38     menuBar()->addMenu(createFileMenu(m_tabWidget));
39     menuBar()->addMenu(createEditMenu());
40     menuBar()->addMenu(createViewMenu(toolbar));
41     menuBar()->addMenu(createWindowMenu(m_tabWidget));
42     menuBar()->addMenu(createHelpMenu());
43 
44     QWidget *centralWidget = new QWidget(this);
45     QVBoxLayout *layout = new QVBoxLayout;
46     layout->setSpacing(0);
47     layout->setMargin(0);
48     addToolBarBreak();
49 
50     m_progressBar->setMaximumHeight(1);
51     m_progressBar->setTextVisible(false);
52     m_progressBar->setStyleSheet(QStringLiteral("QProgressBar {border: 0px} QProgressBar::chunk {background-color: #da4453}"));
53 
54     layout->addWidget(m_progressBar);
55     layout->addWidget(m_tabWidget);
56     centralWidget->setLayout(layout);
57     setCentralWidget(centralWidget);
58 
59     connect(m_tabWidget, &TabWidget::titleChanged, this, &BrowserWindow::handleWebViewTitleChanged);
60     connect(m_tabWidget, &TabWidget::linkHovered, [this](const QString& url) {
61         statusBar()->showMessage(url);
62     });
63     connect(m_tabWidget, &TabWidget::loadProgress, this, &BrowserWindow::handleWebViewLoadProgress);
64     connect(m_tabWidget, &TabWidget::webActionEnabledChanged, this, &BrowserWindow::handleWebActionEnabledChanged);
65     connect(m_tabWidget, &TabWidget::urlChanged, [this](const QUrl &url) {
66         m_urlLineEdit->setText(url.toDisplayString());
67     });
68     connect(m_tabWidget, &TabWidget::favIconChanged, m_favAction, &QAction::setIcon);
69     connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() {
70         m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text()));
71     });
72 
73     QAction *focusUrlLineEditAction = new QAction(this);
74     addAction(focusUrlLineEditAction);
75     focusUrlLineEditAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_L));
76     connect(focusUrlLineEditAction, &QAction::triggered, this, [this] () {
77         m_urlLineEdit->setFocus(Qt::ShortcutFocusReason);
78     });
79 
80     handleWebViewTitleChanged(QString());
81     m_tabWidget->createTab();
82 }
83 
sizeHint() const84 QSize BrowserWindow::sizeHint() const
85 {
86     QRect desktopRect = QApplication::desktop()->screenGeometry();
87     QSize size = desktopRect.size() * qreal(0.9);
88     return size;
89 }
90 
createFileMenu(TabWidget * tabWidget)91 QMenu *BrowserWindow::createFileMenu(TabWidget *tabWidget)
92 {
93     QMenu *fileMenu = new QMenu(tr("&File"));
94     fileMenu->addAction(tr("&New Window"), this, &BrowserWindow::handleNewWindowTriggered, QKeySequence::New);
95     fileMenu->addAction(tr("New &Incognito Window"), this, &BrowserWindow::handleNewIncognitoWindowTriggered);
96 
97     QAction *newTabAction = new QAction(tr("New &Tab"), this);
98     newTabAction->setShortcuts(QKeySequence::AddTab);
99     connect(newTabAction, &QAction::triggered, tabWidget, &TabWidget::createTab);
100     fileMenu->addAction(newTabAction);
101 
102     fileMenu->addAction(tr("&Open File..."), this, &BrowserWindow::handleFileOpenTriggered, QKeySequence::Open);
103     fileMenu->addSeparator();
104 
105     QAction *closeTabAction = new QAction(tr("&Close Tab"), this);
106     closeTabAction->setShortcuts(QKeySequence::Close);
107     connect(closeTabAction, &QAction::triggered, [tabWidget]() {
108         tabWidget->closeTab(tabWidget->currentIndex());
109     });
110     fileMenu->addAction(closeTabAction);
111 
112     QAction *closeAction = new QAction(tr("&Quit"),this);
113     closeAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
114     connect(closeAction, &QAction::triggered, this, &QWidget::close);
115     fileMenu->addAction(closeAction);
116 
117     connect(fileMenu, &QMenu::aboutToShow, [this, closeAction]() {
118         if (m_browser->windows().count() == 1)
119             closeAction->setText(tr("&Quit"));
120         else
121             closeAction->setText(tr("&Close Window"));
122     });
123     return fileMenu;
124 }
125 
createEditMenu()126 QMenu *BrowserWindow::createEditMenu()
127 {
128     QMenu *editMenu = new QMenu(tr("&Edit"));
129     QAction *findAction = editMenu->addAction(tr("&Find"));
130     findAction->setShortcuts(QKeySequence::Find);
131     connect(findAction, &QAction::triggered, this, &BrowserWindow::handleFindActionTriggered);
132 
133     QAction *findNextAction = editMenu->addAction(tr("Find &Next"));
134     findNextAction->setShortcut(QKeySequence::FindNext);
135     connect(findNextAction, &QAction::triggered, [this]() {
136         if (!currentTab() || m_lastSearch.isEmpty())
137             return;
138         currentTab()->findText(m_lastSearch);
139     });
140 
141     QAction *findPreviousAction = editMenu->addAction(tr("Find &Previous"));
142     findPreviousAction->setShortcut(QKeySequence::FindPrevious);
143     connect(findPreviousAction, &QAction::triggered, [this]() {
144         if (!currentTab() || m_lastSearch.isEmpty())
145             return;
146         currentTab()->findText(m_lastSearch, QWebEnginePage::FindBackward);
147     });
148 
149     return editMenu;
150 }
151 
createViewMenu(QToolBar * toolbar)152 QMenu *BrowserWindow::createViewMenu(QToolBar *toolbar)
153 {
154     QMenu *viewMenu = new QMenu(tr("&View"));
155     m_stopAction = viewMenu->addAction(tr("&Stop"));
156     QList<QKeySequence> shortcuts;
157     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Period));
158     shortcuts.append(Qt::Key_Escape);
159     m_stopAction->setShortcuts(shortcuts);
160     connect(m_stopAction, &QAction::triggered, [this]() {
161         m_tabWidget->triggerWebPageAction(QWebEnginePage::Stop);
162     });
163 
164     m_reloadAction = viewMenu->addAction(tr("Reload Page"));
165     m_reloadAction->setShortcuts(QKeySequence::Refresh);
166     connect(m_reloadAction, &QAction::triggered, [this]() {
167         m_tabWidget->triggerWebPageAction(QWebEnginePage::Reload);
168     });
169 
170     QAction *zoomIn = viewMenu->addAction(tr("Zoom &In"));
171     zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
172     connect(zoomIn, &QAction::triggered, [this]() {
173         if (currentTab())
174             currentTab()->setZoomFactor(currentTab()->zoomFactor() + 0.1);
175     });
176 
177     QAction *zoomOut = viewMenu->addAction(tr("Zoom &Out"));
178     zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
179     connect(zoomOut, &QAction::triggered, [this]() {
180         if (currentTab())
181             currentTab()->setZoomFactor(currentTab()->zoomFactor() - 0.1);
182     });
183 
184     QAction *resetZoom = viewMenu->addAction(tr("Reset &Zoom"));
185     resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
186     connect(resetZoom, &QAction::triggered, [this]() {
187         if (currentTab())
188             currentTab()->setZoomFactor(1.0);
189     });
190 
191 
192     viewMenu->addSeparator();
193     QAction *viewToolbarAction = new QAction(tr("Hide Toolbar"),this);
194     viewToolbarAction->setShortcut(tr("Ctrl+|"));
195     connect(viewToolbarAction, &QAction::triggered, [toolbar,viewToolbarAction]() {
196         if (toolbar->isVisible()) {
197             viewToolbarAction->setText(tr("Show Toolbar"));
198             toolbar->close();
199         } else {
200             viewToolbarAction->setText(tr("Hide Toolbar"));
201             toolbar->show();
202         }
203     });
204     viewMenu->addAction(viewToolbarAction);
205 
206     QAction *viewStatusbarAction = new QAction(tr("Hide Status Bar"), this);
207     viewStatusbarAction->setShortcut(tr("Ctrl+/"));
208     connect(viewStatusbarAction, &QAction::triggered, [this, viewStatusbarAction]() {
209         if (statusBar()->isVisible()) {
210             viewStatusbarAction->setText(tr("Show Status Bar"));
211             statusBar()->close();
212         } else {
213             viewStatusbarAction->setText(tr("Hide Status Bar"));
214             statusBar()->show();
215         }
216     });
217     viewMenu->addAction(viewStatusbarAction);
218     return viewMenu;
219 }
220 
createWindowMenu(TabWidget * tabWidget)221 QMenu *BrowserWindow::createWindowMenu(TabWidget *tabWidget)
222 {
223     QMenu *menu = new QMenu(tr("&Window"));
224 
225     QAction *nextTabAction = new QAction(tr("Show Next Tab"), this);
226     QList<QKeySequence> shortcuts;
227     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceRight));
228     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageDown));
229     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketRight));
230     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Less));
231     nextTabAction->setShortcuts(shortcuts);
232     connect(nextTabAction, &QAction::triggered, tabWidget, &TabWidget::nextTab);
233 
234     QAction *previousTabAction = new QAction(tr("Show Previous Tab"), this);
235     shortcuts.clear();
236     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BraceLeft));
237     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_PageUp));
238     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_BracketLeft));
239     shortcuts.append(QKeySequence(Qt::CTRL | Qt::Key_Greater));
240     previousTabAction->setShortcuts(shortcuts);
241     connect(previousTabAction, &QAction::triggered, tabWidget, &TabWidget::previousTab);
242 
243     connect(menu, &QMenu::aboutToShow, [this, menu, nextTabAction, previousTabAction]() {
244         menu->clear();
245         menu->addAction(nextTabAction);
246         menu->addAction(previousTabAction);
247         menu->addSeparator();
248 
249         QVector<BrowserWindow*> windows = m_browser->windows();
250         int index(-1);
251         for (auto window : windows) {
252             QAction *action = menu->addAction(window->windowTitle(), this, &BrowserWindow::handleShowWindowTriggered);
253             action->setData(++index);
254             action->setCheckable(true);
255             if (window == this)
256                 action->setChecked(true);
257         }
258     });
259     return menu;
260 }
261 
createHelpMenu()262 QMenu *BrowserWindow::createHelpMenu()
263 {
264     QMenu *helpMenu = new QMenu(tr("&Help"));
265     helpMenu->addAction(tr("About &Qt"), qApp, QApplication::aboutQt);
266     return helpMenu;
267 }
268 
createToolBar()269 QToolBar *BrowserWindow::createToolBar()
270 {
271     QToolBar *navigationBar = new QToolBar(tr("Navigation"));
272     navigationBar->setMovable(false);
273     navigationBar->toggleViewAction()->setEnabled(false);
274 
275     m_historyBackAction = new QAction(this);
276     QList<QKeySequence> backShortcuts = QKeySequence::keyBindings(QKeySequence::Back);
277     for (auto it = backShortcuts.begin(); it != backShortcuts.end();) {
278         // Chromium already handles navigate on backspace when appropriate.
279         if ((*it)[0] == Qt::Key_Backspace)
280             it = backShortcuts.erase(it);
281         else
282             ++it;
283     }
284     // For some reason Qt doesn't bind the dedicated Back key to Back.
285     backShortcuts.append(QKeySequence(Qt::Key_Back));
286     m_historyBackAction->setShortcuts(backShortcuts);
287     m_historyBackAction->setIconVisibleInMenu(false);
288     m_historyBackAction->setIcon(QIcon(QStringLiteral(":go-previous.png")));
289     m_historyBackAction->setToolTip(tr("Go back in history"));
290     connect(m_historyBackAction, &QAction::triggered, [this]() {
291         m_tabWidget->triggerWebPageAction(QWebEnginePage::Back);
292     });
293     navigationBar->addAction(m_historyBackAction);
294 
295     m_historyForwardAction = new QAction(this);
296     QList<QKeySequence> fwdShortcuts = QKeySequence::keyBindings(QKeySequence::Forward);
297     for (auto it = fwdShortcuts.begin(); it != fwdShortcuts.end();) {
298         if (((*it)[0] & Qt::Key_unknown) == Qt::Key_Backspace)
299             it = fwdShortcuts.erase(it);
300         else
301             ++it;
302     }
303     fwdShortcuts.append(QKeySequence(Qt::Key_Forward));
304     m_historyForwardAction->setShortcuts(fwdShortcuts);
305     m_historyForwardAction->setIconVisibleInMenu(false);
306     m_historyForwardAction->setIcon(QIcon(QStringLiteral(":go-next.png")));
307     m_historyForwardAction->setToolTip(tr("Go forward in history"));
308     connect(m_historyForwardAction, &QAction::triggered, [this]() {
309         m_tabWidget->triggerWebPageAction(QWebEnginePage::Forward);
310     });
311     navigationBar->addAction(m_historyForwardAction);
312 
313     m_stopReloadAction = new QAction(this);
314     connect(m_stopReloadAction, &QAction::triggered, [this]() {
315         m_tabWidget->triggerWebPageAction(QWebEnginePage::WebAction(m_stopReloadAction->data().toInt()));
316     });
317     navigationBar->addAction(m_stopReloadAction);
318 
319     m_urlLineEdit = new QLineEdit(this);
320     m_favAction = new QAction(this);
321     m_urlLineEdit->addAction(m_favAction, QLineEdit::LeadingPosition);
322     m_urlLineEdit->setClearButtonEnabled(true);
323     navigationBar->addWidget(m_urlLineEdit);
324 
325     auto downloadsAction = new QAction(this);
326     downloadsAction->setIcon(QIcon(QStringLiteral(":go-bottom.png")));
327     downloadsAction->setToolTip(tr("Show downloads"));
328     navigationBar->addAction(downloadsAction);
329     connect(downloadsAction, &QAction::triggered, [this]() {
330         m_browser->downloadManagerWidget().show();
331     });
332 
333     return navigationBar;
334 }
335 
handleWebActionEnabledChanged(QWebEnginePage::WebAction action,bool enabled)336 void BrowserWindow::handleWebActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled)
337 {
338     switch (action) {
339     case QWebEnginePage::Back:
340         m_historyBackAction->setEnabled(enabled);
341         break;
342     case QWebEnginePage::Forward:
343         m_historyForwardAction->setEnabled(enabled);
344         break;
345     case QWebEnginePage::Reload:
346         m_reloadAction->setEnabled(enabled);
347         break;
348     case QWebEnginePage::Stop:
349         m_stopAction->setEnabled(enabled);
350         break;
351     default:
352         qWarning("Unhandled webActionChanged signal");
353     }
354 }
355 
handleWebViewTitleChanged(const QString & title)356 void BrowserWindow::handleWebViewTitleChanged(const QString &title)
357 {
358     QString suffix = m_profile->isOffTheRecord()
359         ? tr("Qt Simple Browser (Incognito)")
360         : tr("Qt Simple Browser");
361 
362     if (title.isEmpty())
363         setWindowTitle(suffix);
364     else
365         setWindowTitle(title + " - " + suffix);
366 }
367 
handleNewWindowTriggered()368 void BrowserWindow::handleNewWindowTriggered()
369 {
370     m_browser->createWindow();
371 }
372 
handleNewIncognitoWindowTriggered()373 void BrowserWindow::handleNewIncognitoWindowTriggered()
374 {
375     m_browser->createWindow(/* offTheRecord: */ true);
376 }
377 
handleFileOpenTriggered()378 void BrowserWindow::handleFileOpenTriggered()
379 {
380     QUrl url = QFileDialog::getOpenFileUrl(this, tr("Open Web Resource"), QString(),
381                                                 tr("Web Resources (*.html *.htm *.svg *.png *.gif *.svgz);;All files (*.*)"));
382     if (url.isEmpty())
383         return;
384     currentTab()->setUrl(url);
385 }
386 
handleFindActionTriggered()387 void BrowserWindow::handleFindActionTriggered()
388 {
389     if (!currentTab())
390         return;
391     bool ok = false;
392     QString search = QInputDialog::getText(this, tr("Find"),
393                                            tr("Find:"), QLineEdit::Normal,
394                                            m_lastSearch, &ok);
395     if (ok && !search.isEmpty()) {
396         m_lastSearch = search;
397         currentTab()->findText(m_lastSearch, 0, [this](bool found) {
398             if (!found)
399                 statusBar()->showMessage(tr("\"%1\" not found.").arg(m_lastSearch));
400         });
401     }
402 }
403 
closeEvent(QCloseEvent * event)404 void BrowserWindow::closeEvent(QCloseEvent *event)
405 {
406     if (m_tabWidget->count() > 1) {
407         int ret = QMessageBox::warning(this, tr("Confirm close"),
408                                        tr("Are you sure you want to close the window ?\n"
409                                           "There are %1 tabs open.").arg(m_tabWidget->count()),
410                                        QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
411         if (ret == QMessageBox::No) {
412             event->ignore();
413             return;
414         }
415     }
416     event->accept();
417     deleteLater();
418 }
419 
tabWidget() const420 TabWidget *BrowserWindow::tabWidget() const
421 {
422     return m_tabWidget;
423 }
424 
currentTab() const425 WebView *BrowserWindow::currentTab() const
426 {
427     return m_tabWidget->currentWebView();
428 }
429 
handleWebViewLoadProgress(int progress)430 void BrowserWindow::handleWebViewLoadProgress(int progress)
431 {
432     static QIcon stopIcon(QStringLiteral(":process-stop.png"));
433     static QIcon reloadIcon(QStringLiteral(":view-refresh.png"));
434 
435     if (0 < progress && progress < 100) {
436         m_stopReloadAction->setData(QWebEnginePage::Stop);
437         m_stopReloadAction->setIcon(stopIcon);
438         m_stopReloadAction->setToolTip(tr("Stop loading the current page"));
439         m_progressBar->setValue(progress);
440     } else {
441         m_stopReloadAction->setData(QWebEnginePage::Reload);
442         m_stopReloadAction->setIcon(reloadIcon);
443         m_stopReloadAction->setToolTip(tr("Reload the current page"));
444         m_progressBar->setValue(0);
445     }
446 }
447 
handleShowWindowTriggered()448 void BrowserWindow::handleShowWindowTriggered()
449 {
450     if (QAction *action = qobject_cast<QAction*>(sender())) {
451         int offset = action->data().toInt();
452         QVector<BrowserWindow*> windows = m_browser->windows();
453         windows.at(offset)->activateWindow();
454         windows.at(offset)->currentTab()->setFocus();
455     }
456 }
457