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