/*******************************************************************************
**
** smolbote: yet another qute browser
** Copyright (C) 2017 Xian Nox
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see .
**
******************************************************************************/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "widgets/mainwindowmenubar.h"
#include
#include "forms/aboutdialog.h"
#include
#include
#include
#include
#include
#include
#include
#include "browser.h"
#include
#include
MainWindow::MainWindow(std::shared_ptr config, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
tabBar(new WebViewTabBar(config, nullptr, this)),
menuBar(new MainWindowMenuBar(config, this)),
m_addressBar(new UrlLineEdit(this)),
m_progressBar(new LoadingBar(this))
{
Q_ASSERT(config);
m_config = config;
// delete this window when it closes
setAttribute(Qt::WA_DeleteOnClose, true);
// set up UI
ui->setupUi(this);
QAction *fullscreenAction = new QAction(this);
fullscreenAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value("browser.shortcuts.fullscreen").value())));
connect(fullscreenAction, &QAction::triggered, this, &MainWindow::toggleFullscreen);
addAction(fullscreenAction);
// Dockable widget styling
setDockOptions(dockOptions() | AllowTabbedDocks | ForceTabbedDocks);
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North);
// Add the toolbars
// tabToolBar: main menu and tab list
ui->mainToolBar->setMovable(m_config->value("browser.ui.tabtoolbarMovable").value());
ui->mainToolBar->addWidget(menuBar);
//tabToolBar->addWidget(tabBar);
// navigationToolBar: address bar
ui->navigationToolBar->setMovable(m_config->value("browser.ui.navtoolbarMovable").value());
insertToolBarBreak(ui->navigationToolBar);
// page actions
m_backButton = new NavigationButton(NavigationButton::BackButton, this);
m_forwardButton = new NavigationButton(NavigationButton::ForwardButton, this);
m_reloadButton = new NavigationButton(NavigationButton::ReloadButton, this);
QToolButton *homepageButton = new QToolButton(this);
homepageButton->setIcon(style()->standardIcon(QStyle::SP_DirHomeIcon));
connect(homepageButton, &QToolButton::clicked, this, [&]() {
tabBar->currentView()->load(tabBar->profile()->homepage());
});
ui->navigationToolBar->addWidget(m_backButton);
ui->navigationToolBar->addWidget(m_forwardButton);
ui->navigationToolBar->addWidget(m_reloadButton);
ui->navigationToolBar->addWidget(homepageButton);
ui->navigationToolBar->addWidget(m_addressBar);
// connect signals
connect(m_addressBar, &UrlLineEdit::addressEntered, this, [&](const QUrl &url) {
tabBar->currentView()->load(url);
});
connect(m_addressBar, &UrlLineEdit::searchTermEntered, this, [&](const QString &term) {
QString t = term;
t.replace(' ', '+');
QString url = QString::fromStdString(m_config->value("profile.search").value());
url.replace("$term", t);
tabBar->currentView()->load(QUrl::fromUserInput(url));
});
connect(tabBar, SIGNAL(currentTabChanged(WebView*)), this, SLOT(handleTabChanged(WebView*)));
// loading bar
ui->statusBar->addPermanentWidget(m_progressBar);
// shortcuts
QAction *focusAddressAction = new QAction(this);
focusAddressAction->setShortcut(QKeySequence(QString::fromStdString(m_config->value("browser.shortcuts.focusAddress").value())));
//focusAddressAction->setShortcut(QKeySequence::fromString(browser->settings()->value("window.shortcuts.focusAddress").toString()));
//connect(focusAddressAction, SIGNAL(triggered(bool)), this, SLOT(focusAddress()));
connect(focusAddressAction, &QAction::triggered, this, [this]() {
m_addressBar->setFocus();
m_addressBar->selectAll();
});
addAction(focusAddressAction);
resize(m_config->value("browser.window.width").value(), m_config->value("browser.window.height").value());
if(m_config->value("browser.window.maximized").value()) {
showMaximized();
}
}
MainWindow::~MainWindow()
{
// Release all dock widgets before deleting so we don't accidentally delete them
// Also fixes that annoying crash when closing
QList allDockWidgets = findChildren();
for(QDockWidget *w : allDockWidgets) {
if(w->widget()) {
w->widget()->setParent(nullptr);
}
}
delete ui;
}
void MainWindow::addTabbedDock(Qt::DockWidgetArea area, QWidget *widget)
{
// get all dock widgets
QList allDockWidgets = findChildren();
// make a list of widgets in the area we want
QVector areaDockWidgets;
for(QDockWidget *w : allDockWidgets) {
if(dockWidgetArea(w) == area) {
areaDockWidgets.append(w);
}
}
// create a dock widget
QDockWidget *dock = new QDockWidget(widget->windowTitle(), this);
// release the held widget when deleted
connect(dock, &QDockWidget::destroyed, this, [dock]() {
dock->widget()->setParent(nullptr);
});
dock->setWidget(widget);
if(areaDockWidgets.empty()) {
// no other widgets
addDockWidget(area, dock);
} else {
// there are other widgets, so put it after the last one
tabifyDockWidget(areaDockWidgets.last(), dock);
}
}
void MainWindow::newTab(const QUrl &url)
{
if(!m_tabBarAdded) {
m_tabBarAdded = true;
ui->mainToolBar->addWidget(tabBar);
}
tabBar->addTab(url);
}
void MainWindow::newWindow(const QUrl &url)
{
Browser *instance = static_cast(qApp->instance());
MainWindow *window = instance->createWindow();
window->setProfile(tabBar->profile());
window->newTab(url);
}
void MainWindow::focusAddress()
{
m_addressBar->setFocus();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
if(tabBar->count() > 1) {
int ret = QMessageBox::warning(this, tr("Close window?"), tr("Close multiple tabs?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
if(ret == QMessageBox::No) {
event->ignore();
return;
}
}
QMainWindow::closeEvent(event);
}
void MainWindow::about()
{
AboutDialog *dlg = new AboutDialog(this);
dlg->exec();
}
void MainWindow::showSettingsDialog()
{
SettingsDialog *dlg = new SettingsDialog(m_config, this);
dlg->exec();
}
void MainWindow::setProfile(WebEngineProfile *profile)
{
Q_CHECK_PTR(profile);
tabBar->setProfile(profile);
menuBar->setProfileName(profile->name());
}
WebEngineProfile *MainWindow::profile()
{
Q_CHECK_PTR(tabBar->profile());
return tabBar->profile();
}
void MainWindow::setBookmarksWidget(std::shared_ptr &widget)
{
Q_ASSERT(widget);
m_bookmarksWidget = widget;
connect(menuBar->bookmarksAction(), &QAction::triggered, this, [this]() {
addTabbedDock(Qt::RightDockWidgetArea, m_bookmarksWidget.get());
});
connect(m_bookmarksWidget.get(), &BookmarksWidget::openUrl, this, [this](const QUrl &url) {
if(isActiveWindow()) {
newTab(url);
}
});
}
void MainWindow::setDownloadsWidget(std::shared_ptr &widget)
{
Q_ASSERT(widget);
m_downloadsWidget = widget;
connect(menuBar->downloadsAction(), &QAction::triggered, this, [this]() {
addTabbedDock(Qt::RightDockWidgetArea, m_downloadsWidget.get());
});
}
void MainWindow::toggleFullscreen()
{
if(isFullScreen()) {
setWindowState(Qt::WindowMaximized | Qt::WindowActive);
} else {
setWindowState(Qt::WindowFullScreen | Qt::WindowActive);
}
}
void MainWindow::handleTabChanged(WebView *view)
{
Q_CHECK_PTR(view);
m_currentView = view;
// centralWidget can be a nullptr
if(centralWidget()) {
// clear the parent of the central widget so it doesn't get deleted
centralWidget()->setParent(nullptr);
// disconnect signals
disconnect(centralWidget());
}
// set new central widget
setCentralWidget(view);
// connect signals
m_backButton->setView(view);
m_forwardButton->setView(view);
m_reloadButton->setView(view);
connect(view, &WebView::urlChanged, m_addressBar, &UrlLineEdit::setUrl);
m_addressBar->setUrl(view->url());
m_addressBar->pageAction()->setMenu(view->pageMenu());
connect(view, SIGNAL(titleChanged(QString)), this, SLOT(handleTitleUpdated(QString)));
connect(view, SIGNAL(linkHovered(QString)), ui->statusBar, SLOT(showMessage(QString)));
m_progressBar->connectWebView(view);
// update UI
this->handleTitleUpdated(view->title());
centralWidget()->setFocus();
}
void MainWindow::handleTitleUpdated(const QString &title)
{
QString t = QString::fromStdString(m_config->value("browser.window.title").value());
t.replace("title", title);
t.replace("profile", tabBar->profile()->name());
setWindowTitle(t);
//setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name()));
}