From 49ee5ed6e80b8f06337f92d14e2cab1c1512c1e3 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Fri, 19 Jan 2018 02:10:31 +0100 Subject: Refactoring MainWindow - Added NavigationBar object that manages the navigation buttons - Removed NavigationButton class that it obsoleted --- src/browser.cpp | 2 +- src/forms/searchform.cpp | 2 +- src/main.cpp | 2 +- src/mainwindow.cpp | 332 ------------------------------- src/mainwindow.h | 96 --------- src/mainwindow.ui | 63 ------ src/mainwindow/mainwindow.cpp | 316 +++++++++++++++++++++++++++++ src/mainwindow/mainwindow.h | 98 +++++++++ src/mainwindow/mainwindow.ui | 63 ++++++ src/mainwindow/widgets/loadingbar.cpp | 50 +++++ src/mainwindow/widgets/loadingbar.h | 30 +++ src/mainwindow/widgets/navigationbar.cpp | 115 +++++++++++ src/mainwindow/widgets/navigationbar.h | 55 +++++ src/webengine/webview.cpp | 23 ++- src/webengine/webview.h | 7 +- src/widgets/loadingbar.cpp | 39 ---- src/widgets/loadingbar.h | 29 --- src/widgets/mainwindowmenubar.cpp | 2 +- src/widgets/mainwindowtabbar.cpp | 2 +- 19 files changed, 760 insertions(+), 566 deletions(-) delete mode 100644 src/mainwindow.cpp delete mode 100644 src/mainwindow.h delete mode 100644 src/mainwindow.ui create mode 100644 src/mainwindow/mainwindow.cpp create mode 100644 src/mainwindow/mainwindow.h create mode 100644 src/mainwindow/mainwindow.ui create mode 100644 src/mainwindow/widgets/loadingbar.cpp create mode 100644 src/mainwindow/widgets/loadingbar.h create mode 100644 src/mainwindow/widgets/navigationbar.cpp create mode 100644 src/mainwindow/widgets/navigationbar.h delete mode 100644 src/widgets/loadingbar.cpp delete mode 100644 src/widgets/loadingbar.h (limited to 'src') diff --git a/src/browser.cpp b/src/browser.cpp index 1e07a95..3d2bec0 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -7,7 +7,7 @@ */ #include "browser.h" -#include "mainwindow.h" +#include "src/mainwindow/mainwindow.h" #include "webengine/urlinterceptor.h" #include #include diff --git a/src/forms/searchform.cpp b/src/forms/searchform.cpp index 42e5a1a..bed0dc5 100644 --- a/src/forms/searchform.cpp +++ b/src/forms/searchform.cpp @@ -7,7 +7,7 @@ */ #include "searchform.h" -#include "../mainwindow.h" +#include "src/mainwindow/mainwindow.h" #include "ui_searchform.h" #include diff --git a/src/main.cpp b/src/main.cpp index 0452fdd..62f6757 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,7 +7,7 @@ */ #include "browser.h" -#include "mainwindow.h" +#include "src/mainwindow/mainwindow.h" #include "version.h" #include #include diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp deleted file mode 100644 index 4306afd..0000000 --- a/src/mainwindow.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: git://neueland.iserlohn-fortress.net/smolbote.git - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#include "mainwindow.h" -#include "browser.h" -#include "forms/aboutdialog.h" -#include "forms/searchform.h" -#include "ui_mainwindow.h" -#include "widgets/mainwindowmenubar.h" -#include -#include -#include -#include -#include -#include - -MainWindow::MainWindow(std::shared_ptr config, QWidget *parent) - : QMainWindow(parent) - , ui(new Ui::MainWindow) - , tabBar(new MainWindowTabBar(config, 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(m_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, &MainWindowTabBar::currentTabChanged, this, &MainWindow::handleTabChanged); - //connect(tabBar, SIGNAL(currentTabChanged(WebView *)), this, SLOT(handleTabChanged(WebView *))); - - // loading bar - ui->statusBar->addPermanentWidget(m_progressBar); - - // search box - m_searchBox = new SearchForm(this); - ui->statusBar->addWidget(m_searchBox); - m_searchBox->setVisible(false); - - // 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) -{ - // make a list of widgets in the area we want - // this way we can append the new dock widget to the last one - QVector areaDockWidgets; - for(QDockWidget *w : findChildren()) { - // check if widget is already shown - if(w->widget() == widget) { - // in this case, close the dock and return - w->close(); - return; - } - - if(dockWidgetArea(w) == area) { - areaDockWidgets.append(w); - } - } - - // create a dock widget - QDockWidget *dock = new QDockWidget(widget->windowTitle(), this); - dock->setAttribute(Qt::WA_DeleteOnClose, true); - - // when the dock widget becomes invisble, release the docked widget - // setting the widget makes the dock its parent; setting parent back to nullptr - // makes the dock not show the widget any more - connect(dock, &QDockWidget::visibilityChanged, [dock](bool visible) { - if(!visible && dock->widget()) { - dock->widget()->setParent(nullptr); - } - }); - dock->setWidget(widget); - - // the same widget may be shown by docks in other windows - // in that case, they grab ownership and the current dock won't be showing anything - // so the current widget needs to be closed - auto *w = dynamic_cast(widget); - w->closeOthers(); - if(w) { - connect(w, &BookmarksWidget::closeOthersSignal, dock, [dock]() { - dock->close(); - }); - } - - 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(createWebView(url, m_profile.get(), this)); -} - -MainWindow *MainWindow::newWindow(const QUrl &url) -{ - Browser *instance = static_cast(qApp->instance()); - return instance->createSession(m_profile->storageName(), true, QStringList(url.toString())); -} - -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(std::shared_ptr profile) -{ - Q_ASSERT(profile); - m_profile = profile; - tabBar->setProfile(profile.get()); - menuBar->setProfileName(profile->name()); -} - -WebEngineProfile *MainWindow::profile() -{ - Q_ASSERT(m_profile); - return m_profile.get(); -} - -void MainWindow::setBookmarksWidget(std::shared_ptr &widget) -{ - Q_ASSERT(widget); - m_bookmarksWidget = widget; - m_addressBar->setCompleterModel(m_bookmarksWidget->model()); - 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; -} - -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, &WebView::titleChanged, this, &MainWindow::handleTitleUpdated); - - 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", m_profile->name()); - setWindowTitle(t); - //setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name())); -} - -void MainWindow::addPlugins(const QVector &plugins) -{ - for(const Browser::Plugin &plugin : plugins) { - ProfileInterface *iProfilePlugin = qobject_cast(plugin.pointer); - if(iProfilePlugin) { - QWidget *w = iProfilePlugin->createWidget(m_profile.get(), this); - - auto *profileAction = new QAction(tr("Profile Action"), this); - ui->navigationToolBar->addAction(profileAction); - connect(profileAction, &QAction::triggered, this, [this, w]() { - w->setVisible(!w->isVisible()); - if(w->isVisible()) { - QPoint pos = ui->navigationToolBar->pos(); - pos.setX(pos.x() + ui->navigationToolBar->width() - w->width()); - pos.setY(pos.y() + ui->navigationToolBar->height()); - w->move(mapToGlobal(pos)); - w->show(); - } - }); - } - } -} diff --git a/src/mainwindow.h b/src/mainwindow.h deleted file mode 100644 index 79773d3..0000000 --- a/src/mainwindow.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: git://neueland.iserlohn-fortress.net/smolbote.git - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include "browser.h" -#include "lib/navigation/navigationbutton.h" -#include "webengine/webengineprofile.h" -#include "widgets/loadingbar.h" -#include "widgets/mainwindowtabbar.h" -#include -#include -#include -#include - -namespace Ui -{ -class MainWindow; -} - -class SearchForm; - -class Configuration; -class BookmarksWidget; -class DownloadsWidget; - -class MainWindowMenuBar; -class UrlLineEdit; - -class MainWindow : public QMainWindow -{ - Q_OBJECT - - friend class WebView; - friend class SearchForm; - - friend class MainWindowMenuBar; - -public: - explicit MainWindow(std::shared_ptr config, QWidget *parent = nullptr); - Q_DISABLE_COPY(MainWindow) - ~MainWindow() override; - - void addTabbedDock(Qt::DockWidgetArea area, QWidget *widget); - -public slots: - void about(); - void showSettingsDialog(); - - void newTab(const QUrl &url = QUrl("")); - MainWindow *newWindow(const QUrl &url = QUrl("")); - - void setProfile(std::shared_ptr profile); - WebEngineProfile *profile(); - - void setBookmarksWidget(std::shared_ptr &widget); - void setDownloadsWidget(std::shared_ptr &widget); - void addPlugins(const QVector &plugins); - - void toggleFullscreen(); - -protected: - void closeEvent(QCloseEvent *event) override; - -private slots: - void handleTabChanged(WebView *view); - void handleTitleUpdated(const QString &title); - -private: - Ui::MainWindow *ui; - SearchForm *m_searchBox; - - MainWindowTabBar *tabBar; - WebView *m_currentView; - - MainWindowMenuBar *menuBar; - - // navigation - NavigationButton *m_backButton, *m_forwardButton, *m_reloadButton; - UrlLineEdit *m_addressBar; - LoadingBar *m_progressBar; - - bool m_tabBarAdded = false; - std::shared_ptr m_profile; - std::shared_ptr m_config; - std::shared_ptr m_bookmarksWidget; - std::shared_ptr m_downloadsWidget; -}; - -#endif // MAINWINDOW_H diff --git a/src/mainwindow.ui b/src/mainwindow.ui deleted file mode 100644 index 12a3a6c..0000000 --- a/src/mainwindow.ui +++ /dev/null @@ -1,63 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 400 - 300 - - - - MainWindow - - - - - - 0 - 0 - - - - - 16777215 - 24 - - - - - - Main - - - Qt::TopToolBarArea - - - TopToolBarArea - - - false - - - - - Navigation - - - Qt::TopToolBarArea - - - TopToolBarArea - - - false - - - - - - - diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp new file mode 100644 index 0000000..018ff64 --- /dev/null +++ b/src/mainwindow/mainwindow.cpp @@ -0,0 +1,316 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "mainwindow.h" +#include "forms/aboutdialog.h" +#include "forms/searchform.h" +#include "ui_mainwindow.h" +#include "widgets/mainwindowmenubar.h" +#include +#include +#include +#include +#include +#include + +MainWindow::MainWindow(std::shared_ptr config, QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::MainWindow) + , tabBar(new MainWindowTabBar(config, 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_navigationBar = new NavigationBar(this); + m_navigationBar->addWidgetsTo(ui->navigationToolBar); + + 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, &MainWindowTabBar::currentTabChanged, this, &MainWindow::handleTabChanged); + //connect(tabBar, SIGNAL(currentTabChanged(WebView *)), this, SLOT(handleTabChanged(WebView *))); + + // loading bar + ui->statusBar->addPermanentWidget(m_progressBar); + + // search box + m_searchBox = new SearchForm(this); + ui->statusBar->addWidget(m_searchBox); + m_searchBox->setVisible(false); + + // 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) +{ + // make a list of widgets in the area we want + // this way we can append the new dock widget to the last one + QVector areaDockWidgets; + for(QDockWidget *w : findChildren()) { + // check if widget is already shown + if(w->widget() == widget) { + // in this case, close the dock and return + w->close(); + return; + } + + if(dockWidgetArea(w) == area) { + areaDockWidgets.append(w); + } + } + + // create a dock widget + QDockWidget *dock = new QDockWidget(widget->windowTitle(), this); + dock->setAttribute(Qt::WA_DeleteOnClose, true); + + // when the dock widget becomes invisble, release the docked widget + // setting the widget makes the dock its parent; setting parent back to nullptr + // makes the dock not show the widget any more + connect(dock, &QDockWidget::visibilityChanged, [dock](bool visible) { + if(!visible && dock->widget()) { + dock->widget()->setParent(nullptr); + } + }); + dock->setWidget(widget); + + // the same widget may be shown by docks in other windows + // in that case, they grab ownership and the current dock won't be showing anything + // so the current widget needs to be closed + auto *w = dynamic_cast(widget); + w->closeOthers(); + if(w) { + connect(w, &BookmarksWidget::closeOthersSignal, dock, [dock]() { + dock->close(); + }); + } + + 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(createWebView(url, m_profile.get(), this)); +} + +MainWindow *MainWindow::newWindow(const QUrl &url) +{ + Browser *instance = static_cast(qApp->instance()); + return instance->createSession(m_profile->storageName(), true, QStringList(url.toString())); +} + +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(std::shared_ptr profile) +{ + Q_ASSERT(profile); + m_profile = profile; + tabBar->setProfile(profile.get()); + menuBar->setProfileName(profile->name()); +} + +WebEngineProfile *MainWindow::profile() +{ + Q_ASSERT(m_profile); + return m_profile.get(); +} + +void MainWindow::setBookmarksWidget(std::shared_ptr &widget) +{ + Q_ASSERT(widget); + m_bookmarksWidget = widget; + m_addressBar->setCompleterModel(m_bookmarksWidget->model()); + 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; +} + +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_navigationBar->connectWebView(view); + + connect(view, &WebView::urlChanged, m_addressBar, &UrlLineEdit::setUrl); + m_addressBar->setUrl(view->url()); + m_addressBar->pageAction()->setMenu(view->pageMenu()); + + connect(view, &WebView::titleChanged, this, &MainWindow::handleTitleUpdated); + + 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", m_profile->name()); + setWindowTitle(t); + //setWindowTitle(browser->settings()->value("window.title").toString().replace("title", title).replace("profile", tabBar->profile()->name())); +} + +void MainWindow::addPlugins(const QVector &plugins) +{ + for(const Browser::Plugin &plugin : plugins) { + ProfileInterface *iProfilePlugin = qobject_cast(plugin.pointer); + if(iProfilePlugin) { + QWidget *w = iProfilePlugin->createWidget(m_profile.get(), this); + + auto *profileAction = new QAction(tr("Profile Action"), this); + ui->navigationToolBar->addAction(profileAction); + connect(profileAction, &QAction::triggered, this, [this, w]() { + w->setVisible(!w->isVisible()); + if(w->isVisible()) { + QPoint pos = ui->navigationToolBar->pos(); + pos.setX(pos.x() + ui->navigationToolBar->width() - w->width()); + pos.setY(pos.y() + ui->navigationToolBar->height()); + w->move(mapToGlobal(pos)); + w->show(); + } + }); + } + } +} diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h new file mode 100644 index 0000000..3f2c3a2 --- /dev/null +++ b/src/mainwindow/mainwindow.h @@ -0,0 +1,98 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "browser.h" +#include "webengine/webengineprofile.h" +#include "widgets/loadingbar.h" +#include "widgets/navigationbar.h" +#include "widgets/mainwindowtabbar.h" +#include +#include +#include +#include + +namespace Ui +{ +class MainWindow; +} + +class SearchForm; + +class Configuration; +class BookmarksWidget; +class DownloadsWidget; + +class MainWindowMenuBar; +class UrlLineEdit; + +class MainWindow : public QMainWindow +{ + Q_OBJECT + + friend class WebView; + friend class SearchForm; + + friend class MainWindowMenuBar; + + friend class NavigationBar; + +public: + explicit MainWindow(std::shared_ptr config, QWidget *parent = nullptr); + Q_DISABLE_COPY(MainWindow) + ~MainWindow() override; + + void addTabbedDock(Qt::DockWidgetArea area, QWidget *widget); + +public slots: + void about(); + void showSettingsDialog(); + + void newTab(const QUrl &url = QUrl("")); + MainWindow *newWindow(const QUrl &url = QUrl("")); + + void setProfile(std::shared_ptr profile); + WebEngineProfile *profile(); + + void setBookmarksWidget(std::shared_ptr &widget); + void setDownloadsWidget(std::shared_ptr &widget); + void addPlugins(const QVector &plugins); + + void toggleFullscreen(); + +protected: + void closeEvent(QCloseEvent *event) override; + +private slots: + void handleTabChanged(WebView *view); + void handleTitleUpdated(const QString &title); + +private: + Ui::MainWindow *ui; + SearchForm *m_searchBox; + + MainWindowTabBar *tabBar; + WebView *m_currentView; + + MainWindowMenuBar *menuBar; + + // navigation + NavigationBar *m_navigationBar; + UrlLineEdit *m_addressBar; + LoadingBar *m_progressBar; + + bool m_tabBarAdded = false; + std::shared_ptr m_profile; + std::shared_ptr m_config; + std::shared_ptr m_bookmarksWidget; + std::shared_ptr m_downloadsWidget; +}; + +#endif // MAINWINDOW_H diff --git a/src/mainwindow/mainwindow.ui b/src/mainwindow/mainwindow.ui new file mode 100644 index 0000000..12a3a6c --- /dev/null +++ b/src/mainwindow/mainwindow.ui @@ -0,0 +1,63 @@ + + + MainWindow + + + + 0 + 0 + 400 + 300 + + + + MainWindow + + + + + + 0 + 0 + + + + + 16777215 + 24 + + + + + + Main + + + Qt::TopToolBarArea + + + TopToolBarArea + + + false + + + + + Navigation + + + Qt::TopToolBarArea + + + TopToolBarArea + + + false + + + + + + + diff --git a/src/mainwindow/widgets/loadingbar.cpp b/src/mainwindow/widgets/loadingbar.cpp new file mode 100644 index 0000000..99f44d2 --- /dev/null +++ b/src/mainwindow/widgets/loadingbar.cpp @@ -0,0 +1,50 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "loadingbar.h" +#include +#include "webengine/webview.h" + +LoadingBar::LoadingBar(QWidget *parent) + : QProgressBar(parent) +{ + setMaximum(100); +} + +void LoadingBar::connectWebView(WebView *view) +{ + Q_CHECK_PTR(view); + + disconnect(loadStartedConnection); + disconnect(loadProgressConnection); + disconnect(loadFinishedConnection); + + if(view->isLoaded()) { + this->hide(); + } else { + loadStarted(); + setValue(view->loadProgress()); + } + + loadStartedConnection = connect(view, &QWebEngineView::loadStarted, this, &LoadingBar::loadStarted); + loadProgressConnection = connect(view, &QWebEngineView::loadProgress, this, &QProgressBar::setValue); + loadFinishedConnection = connect(view, &QWebEngineView::loadFinished, this, &LoadingBar::loadFinished); +} + +void LoadingBar::loadStarted() +{ + resetFormat(); + show(); + setValue(0); +} + +void LoadingBar::loadFinished(bool ok) +{ + setFormat(QString("%p% %1").arg(ok ? tr("Finished") : tr("Failed"))); + QTimer::singleShot(2000, this, SLOT(hide())); +} diff --git a/src/mainwindow/widgets/loadingbar.h b/src/mainwindow/widgets/loadingbar.h new file mode 100644 index 0000000..8ae314e --- /dev/null +++ b/src/mainwindow/widgets/loadingbar.h @@ -0,0 +1,30 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef LOADINGBAR_H +#define LOADINGBAR_H + +#include + +class WebView; +class LoadingBar : public QProgressBar +{ + Q_OBJECT +public: + explicit LoadingBar(QWidget *parent = nullptr); + void connectWebView(WebView *view); + +private slots: + void loadStarted(); + void loadFinished(bool ok); + +private: + QMetaObject::Connection loadStartedConnection, loadProgressConnection, loadFinishedConnection; +}; + +#endif // LOADINGBAR_H diff --git a/src/mainwindow/widgets/navigationbar.cpp b/src/mainwindow/widgets/navigationbar.cpp new file mode 100644 index 0000000..648bb23 --- /dev/null +++ b/src/mainwindow/widgets/navigationbar.cpp @@ -0,0 +1,115 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "navigationbar.h" +#include "mainwindow/mainwindow.h" +#include "webengine/webview.h" +#include +#include +#include +#include +#include + +NavigationBar::NavigationBar(MainWindow *parent) + : QObject(parent) +{ + qStyle = parent->style(); + + backButton = new QToolButton(parent); + backButton->setIcon(qStyle->standardIcon(QStyle::SP_ArrowBack)); + connect(backButton, &QToolButton::clicked, this, [this]() { + m_view->history()->back(); + }); + + auto *backMenu = new QMenu(backButton); + backButton->setMenu(backMenu); + connect(backMenu, &QMenu::aboutToShow, this, [this, backMenu]() { + backMenu->clear(); + const QList items = m_view->history()->backItems(10); + for(const QWebEngineHistoryItem &i : items) { + QAction *a = backMenu->addAction(i.title()); + connect(a, &QAction::triggered, this, [i, this]() { + m_view->history()->goToItem(i); + }); + } + }); + + forwardButton = new QToolButton(parent); + forwardButton->setIcon(qStyle->standardIcon(QStyle::SP_ArrowForward)); + connect(forwardButton, &QToolButton::clicked, this, [this]() { + m_view->history()->forward(); + }); + + auto *forwardMenu = new QMenu(forwardButton); + forwardButton->setMenu(forwardMenu); + connect(forwardMenu, &QMenu::aboutToShow, this, [this, forwardMenu]() { + forwardMenu->clear(); + const QList items = m_view->history()->forwardItems(10); + for(const QWebEngineHistoryItem &i : items) { + QAction *a = forwardMenu->addAction(i.title()); + connect(a, &QAction::triggered, this, [i, this]() { + m_view->history()->goToItem(i); + }); + } + }); + + stopReloadButton = new QToolButton(parent); + stopReloadButton->setIcon(qStyle->standardIcon(QStyle::SP_BrowserReload)); + connect(stopReloadButton, &QToolButton::clicked, this, [this]() { + if(m_view->isLoaded()) + m_view->reload(); + else + m_view->stop(); + }); + + homeButton = new QToolButton(parent); + homeButton->setIcon(qStyle->standardIcon(QStyle::SP_DirHomeIcon)); + connect(homeButton, &QToolButton::clicked, this, [this, parent]() { + m_view->load(parent->m_profile->homepage()); + }); +} + +void NavigationBar::addWidgetsTo(QToolBar *toolBar) +{ + toolBar->addWidget(backButton); + toolBar->addWidget(forwardButton); + toolBar->addWidget(stopReloadButton); + toolBar->addWidget(homeButton); +} + +void NavigationBar::connectWebView(WebView *view) +{ + Q_CHECK_PTR(view); + m_view = view; + + disconnect(loadStartedConnection); + disconnect(loadFinishedConnection); + + if(view->isLoaded()) { + update_loadFinished(); + } else { + update_loadStarted(); + } + + loadStartedConnection = connect(view, &QWebEngineView::loadStarted, this, &NavigationBar::update_loadStarted); + loadFinishedConnection = connect(view, &QWebEngineView::loadFinished, this, &NavigationBar::update_loadFinished); +} + +void NavigationBar::update_loadStarted() +{ + backButton->setEnabled(m_view->history()->canGoForward()); + forwardButton->setEnabled(m_view->history()->canGoForward()); + stopReloadButton->setIcon(qStyle->standardIcon(QStyle::SP_BrowserStop)); +} + +void NavigationBar::update_loadFinished() +{ + backButton->setEnabled(m_view->history()->canGoBack()); + forwardButton->setEnabled(m_view->history()->canGoForward()); + stopReloadButton->setIcon(qStyle->standardIcon(QStyle::SP_BrowserReload)); +} diff --git a/src/mainwindow/widgets/navigationbar.h b/src/mainwindow/widgets/navigationbar.h new file mode 100644 index 0000000..15a9c7b --- /dev/null +++ b/src/mainwindow/widgets/navigationbar.h @@ -0,0 +1,55 @@ +/* + * This file is part of smolbote. It's copyrighted by the contributors recorded + * in the version control history of the file, available from its original + * location: git://neueland.iserlohn-fortress.net/smolbote.git + * + * SPDX-License-Identifier: GPL-3.0 + */ + +/* + * Why is this class a QObject and not a QWidget, and why don't we add the + * NavigationBar itself to the toolbar? + * That was the original idea: make a NavBar class, friend it from MainWindow + * to gain access to the config, but there's a couple of issues: + * - adding QToolButtons to a widget that's inside a toolbar makes the buttons + * look absolutely hideous: they're smaller and have a border for some reason + * - if you stylesheet the border away (which is a pain), they're still not + * the same size + * And so we ended up having this class only exist to contain all of the logic + * for the nav buttons (which cuts down the code in MainWindow). + */ + +#ifndef NAVIGATIONBAR_H +#define NAVIGATIONBAR_H + +#include + +class QStyle; +class QToolBar; +class QToolButton; +class MainWindow; +class WebView; +class NavigationBar : public QObject +{ + Q_OBJECT +public: + explicit NavigationBar(MainWindow *parent = nullptr); + + void addWidgetsTo(QToolBar *toolBar); + void connectWebView(WebView *view); + +private slots: + void update_loadStarted(); + void update_loadFinished(); + +private: + QStyle *qStyle; + WebView *m_view; + QToolButton *backButton, *forwardButton; + QToolButton *stopReloadButton; + QToolButton *homeButton; + + QMetaObject::Connection loadStartedConnection, loadFinishedConnection; +}; + +#endif //NAVIGATIONBAR_H diff --git a/src/webengine/webview.cpp b/src/webengine/webview.cpp index ea0ee26..c924144 100644 --- a/src/webengine/webview.cpp +++ b/src/webengine/webview.cpp @@ -26,7 +26,7 @@ #include #include -#include "mainwindow.h" +#include "src/mainwindow/mainwindow.h" #include // ssl errors @@ -38,6 +38,17 @@ WebView::WebView(MainWindow *parentMainWindow, QWidget *parent) Q_CHECK_PTR(parentMainWindow); m_parent = parentMainWindow; + // load status and progress + connect(this, &QWebEngineView::loadStarted, this, [this]() { + m_loaded = false; + }); + connect(this, &QWebEngineView::loadFinished, this, [this]() { + m_loaded = true; + }); + connect(this, &QWebEngineView::loadProgress, this, [this](int progress) { + m_loadProgress = progress; + }); + m_pageMenu = new QMenu(); m_pageMenu->setMinimumWidth(240); @@ -137,6 +148,16 @@ void WebView::setPage(WebPage *page) QWebEngineView::setPage(page); } +bool WebView::isLoaded() const +{ + return m_loaded; +} + +int WebView::loadProgress() const +{ + return m_loadProgress; +} + WebView *WebView::createWindow(QWebEnginePage::WebWindowType type) { WebView *view = new WebView(m_parent); diff --git a/src/webengine/webview.h b/src/webengine/webview.h index 18a1e02..78b85ce 100644 --- a/src/webengine/webview.h +++ b/src/webengine/webview.h @@ -24,12 +24,14 @@ public: QMenu *pageMenu(); void setPage(WebPage *page); + bool isLoaded() const; + int loadProgress() const; signals: void newBookmark(const QString &title, const QUrl &url); protected: - WebView *createWindow(QWebEnginePage::WebWindowType type); + WebView *createWindow(QWebEnginePage::WebWindowType type) override; private slots: void handleLinkHovered(const QString &url); @@ -38,6 +40,9 @@ private slots: private: MainWindow *m_parent = nullptr; QMenu *m_pageMenu = nullptr; + + bool m_loaded; + int m_loadProgress; }; #endif // WEBVIEW_H diff --git a/src/widgets/loadingbar.cpp b/src/widgets/loadingbar.cpp deleted file mode 100644 index e72c5bb..0000000 --- a/src/widgets/loadingbar.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: git://neueland.iserlohn-fortress.net/smolbote.git - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#include "loadingbar.h" -#include -#include - -LoadingBar::LoadingBar(QWidget *parent) - : QProgressBar(parent) -{ - setMaximum(100); -} - -void LoadingBar::connectWebView(QWebEngineView *view) -{ - disconnect(this); - - connect(view, SIGNAL(loadStarted()), this, SLOT(loadStarted())); - connect(view, SIGNAL(loadProgress(int)), this, SLOT(setValue(int))); - connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool))); -} - -void LoadingBar::loadStarted() -{ - resetFormat(); - show(); - setValue(0); -} - -void LoadingBar::loadFinished(bool ok) -{ - setFormat(QString("%p% %1").arg(ok ? tr("Finished") : tr("Failed"))); - QTimer::singleShot(2000, this, SLOT(hide())); -} diff --git a/src/widgets/loadingbar.h b/src/widgets/loadingbar.h deleted file mode 100644 index e281628..0000000 --- a/src/widgets/loadingbar.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of smolbote. It's copyrighted by the contributors recorded - * in the version control history of the file, available from its original - * location: git://neueland.iserlohn-fortress.net/smolbote.git - * - * SPDX-License-Identifier: GPL-3.0 - */ - -#ifndef LOADINGBAR_H -#define LOADINGBAR_H - -#include - -class QWebEngineView; -class LoadingBar : public QProgressBar -{ - Q_OBJECT -public: - explicit LoadingBar(QWidget *parent = 0); - void connectWebView(QWebEngineView *view); - -signals: - -public slots: - void loadStarted(); - void loadFinished(bool ok); -}; - -#endif // LOADINGBAR_H diff --git a/src/widgets/mainwindowmenubar.cpp b/src/widgets/mainwindowmenubar.cpp index f8275c0..bc86e77 100644 --- a/src/widgets/mainwindowmenubar.cpp +++ b/src/widgets/mainwindowmenubar.cpp @@ -8,7 +8,7 @@ #include "mainwindowmenubar.h" #include "downloads/downloadswidget.h" -#include "mainwindow.h" +#include "src/mainwindow/mainwindow.h" #include MainWindowMenuBar::MainWindowMenuBar(std::shared_ptr config, MainWindow *parent) diff --git a/src/widgets/mainwindowtabbar.cpp b/src/widgets/mainwindowtabbar.cpp index 5cf360d..e669bf6 100644 --- a/src/widgets/mainwindowtabbar.cpp +++ b/src/widgets/mainwindowtabbar.cpp @@ -11,7 +11,7 @@ #include #include -#include "mainwindow.h" +#include "src/mainwindow/mainwindow.h" MainWindowTabBar::MainWindowTabBar(const std::shared_ptr &config, MainWindow *parent) : QTabBar(parent) -- cgit v1.2.1