aboutsummaryrefslogtreecommitdiff
path: root/src/mainwindow/mainwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mainwindow/mainwindow.cpp')
-rw-r--r--src/mainwindow/mainwindow.cpp316
1 files changed, 316 insertions, 0 deletions
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 <QDockWidget>
+#include <QMessageBox>
+#include <bookmarks/bookmarkswidget.h>
+#include <downloads/downloadswidget.h>
+#include <navigation/urllineedit.h>
+#include <settings/settingsdialog.h>
+
+MainWindow::MainWindow(std::shared_ptr<Configuration> 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<std::string>("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<bool>("browser.ui.tabtoolbarMovable").value());
+ ui->mainToolBar->addWidget(menuBar);
+ //tabToolBar->addWidget(tabBar);
+
+ // navigationToolBar: address bar
+ ui->navigationToolBar->setMovable(m_config->value<bool>("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<std::string>("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<std::string>("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<int>("browser.window.width").value(), m_config->value<int>("browser.window.height").value());
+ if(m_config->value<bool>("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<QDockWidget *> allDockWidgets = findChildren<QDockWidget *>();
+ 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<QDockWidget *> areaDockWidgets;
+ for(QDockWidget *w : findChildren<QDockWidget *>()) {
+ // 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<BookmarksWidget *>(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<Browser *>(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<WebEngineProfile> 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<BookmarksWidget> &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<DownloadsWidget> &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<std::string>("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<Browser::Plugin> &plugins)
+{
+ for(const Browser::Plugin &plugin : plugins) {
+ ProfileInterface *iProfilePlugin = qobject_cast<ProfileInterface *>(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();
+ }
+ });
+ }
+ }
+}