/*******************************************************************************
**
** 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 "browser.h"
#include
#include
#include "forms/aboutdialog.h"
#include
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
navigationToolBar(new QToolBar(tr("Navigation"), this)),
tabToolBar(new QToolBar(tr("Tab bar"), this)),
tabBar(new WebViewTabBar(nullptr, this)),
m_addressBar(new AddressBar(navigationToolBar)),
m_progressBar(new LoadingBar(this))
{
// 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::fromString(browser->settings()->value("window.shortcuts.fullscreen").toString()));
connect(fullscreenAction, SIGNAL(triggered(bool)), this, SLOT(toggleFullscreen()));
addAction(fullscreenAction);
// Dockable widget styling
setDockOptions(dockOptions() | AllowTabbedDocks | ForceTabbedDocks);
setTabPosition(Qt::LeftDockWidgetArea, QTabWidget::North);
setTabPosition(Qt::RightDockWidgetArea, QTabWidget::North);
// Main menu
MainWindowMenuBar *menuBar = new MainWindowMenuBar(this);
menuBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
connect(menuBar->printAction(), &QAction::triggered, this, [&]() {
const QString path = QFileDialog::getSaveFileName(this, tr("Print to PDF"), QDir::homePath(), tr("PDF files (*.pdf)"));
m_currentView->page()->printToPdf(path);
});
// Add the toolbars
// tabToolBar: main menu and tab list
tabToolBar->setMovable(browser->settings()->value("window.ui.tabtoolbarMovable").toBool());
tabToolBar->addWidget(menuBar);
//tabToolBar->addWidget(tabBar);
this->addToolBar(Qt::TopToolBarArea, tabToolBar);
this->addToolBarBreak(Qt::TopToolBarArea);
// navigationToolBar: address bar
navigationToolBar->setMovable(browser->settings()->value("window.ui.navtoolbarMovable").toBool());
// 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());
});
navigationToolBar->addWidget(m_backButton);
navigationToolBar->addWidget(m_forwardButton);
navigationToolBar->addWidget(m_reloadButton);
navigationToolBar->addWidget(homepageButton);
navigationToolBar->addWidget(m_addressBar);
this->addToolBar(Qt::TopToolBarArea, navigationToolBar);
// connect signals
connect(m_addressBar, &AddressBar::addressEntered, this, [&](const QUrl &url) {
tabBar->currentView()->load(url);
});
connect(m_addressBar, &AddressBar::searchTermEntered, this, [&](const QString &string) {
QString term = string.mid(1);
term.replace(' ', '+');
tabBar->currentView()->load(QUrl::fromUserInput(browser->settings()->value("general.search").toString().replace("$term", term)));
});
connect(tabBar, SIGNAL(currentTabChanged(WebView*)), this, SLOT(handleTabChanged(WebView*)));
connect(browser->bookmarks(), &BookmarksWidget::openUrl, this, [&](const QUrl &url) {
if(this->isActiveWindow()) {
this->newTab(url);
}
});
// Load profile
tabBar->setProfile(browser->profile(browser->settings()->value("browser.profile.default").toString()));
// Adding a tab here, because otherwise tabs won't show up
//newTab();
// loading bar
ui->statusBar->addPermanentWidget(m_progressBar);
// shortcuts
QAction *focusAddressAction = new QAction(this);
focusAddressAction->setShortcut(QKeySequence::fromString(browser->settings()->value("window.shortcuts.focusAddress").toString()));
connect(focusAddressAction, SIGNAL(triggered(bool)), this, SLOT(focusAddress()));
addAction(focusAddressAction);
resize(browser->settings()->value("window.width").toInt(), browser->settings()->value("window.height").toInt());
if(browser->settings()->value("window.maximized").toBool()) {
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(0);
}
}
delete ui;
}
void MainWindow::addTabbedDock(Qt::DockWidgetArea area, QWidget *widget)
{
// create a list for the dock widgets we're appending to
QList allDockWidgets = findChildren();
QVector areaDockWidgets;
for(QDockWidget *w : allDockWidgets) {
if(dockWidgetArea(w) == area) {
areaDockWidgets.append(w);
}
}
QDockWidget *dock = new QDockWidget(widget->windowTitle(), this);
dock->setWidget(widget);
if(areaDockWidgets.empty()) {
// no other widgets
addDockWidget(area, dock);
} else {
tabifyDockWidget(areaDockWidgets.last(), dock);
}
}
void MainWindow::newTab(const QUrl &url)
{
if(!m_tabBarAdded) {
m_tabBarAdded = true;
tabToolBar->addWidget(tabBar);
}
tabBar->addTab(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::setProfile(WebEngineProfile *profile)
{
Q_ASSERT(profile != nullptr);
tabBar->setProfile(profile);
}
void MainWindow::toggleFullscreen()
{
if(isFullScreen()) {
setWindowState(Qt::WindowMaximized | Qt::WindowActive);
} else {
setWindowState(Qt::WindowFullScreen | Qt::WindowActive);
}
}
void MainWindow::newWindow(const QUrl &url)
{
QHash options;
options.insert("urls", url);
browser->createWindow(options);
}
void MainWindow::handleTabChanged(WebView *view)
{
Q_ASSERT(view != nullptr);
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(0);
// disconnect signals
disconnect(centralWidget());
}
// set new central widget
setCentralWidget(view);
// connect signals
m_backButton->setView(view);
m_forwardButton->setView(view);
m_reloadButton->setView(view);
m_addressBar->setWebView(view);
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)
{
setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name()));
}