From d796821f8304306dbe088701724243b39e8eb358 Mon Sep 17 00:00:00 2001 From: Aqua-sama Date: Mon, 16 Apr 2018 17:07:36 +0200 Subject: Multiple subwindows interface Subwindows are similar to tab groups. - Rewrote Browser and MainWindow, so they should be somewhat cleaner now - Moved AboutDialog to lib/about What's broken: - loading bar - search box - address bar bookmark suggestions - plugins --- src/mainwindow/mainwindow.cpp | 362 ++++++++++++++---------------------------- 1 file changed, 115 insertions(+), 247 deletions(-) (limited to 'src/mainwindow/mainwindow.cpp') diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index 99a80b8..c039c8e 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -7,301 +7,169 @@ */ #include "mainwindow.h" -#include "addressbar/urllineedit.h" -#include "configuration/configuration.h" -#include "forms/aboutdialog.h" -#include "mainwindow/widgets/searchform.h" -#include "ui_mainwindow.h" -#include "widgets/mainwindowmenubar.h" -#include "mainwindow/widgets/tabbar.h" +#include "webengine/webview.h" +#include "widgets/navigationbar.h" +#include "window.h" +#include +#include #include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include +#include +#include +#include -MainWindow::MainWindow(std::shared_ptr config, QWidget *parent) +MainWindow::MainWindow(std::shared_ptr &config, QWidget *parent) : QMainWindow(parent) - , ui(new Ui::MainWindow) - , tabBar(new TabBar(config->section("tabbar"), this)) - , m_addressBar(new UrlLineEdit(config->section("addressbar"), this)) - , m_progressBar(new LoadingBar(this)) - , menuBar(new MainWindowMenuBar(config, this)) + , mdiArea(new QMdiArea(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); + // create UI + resize(config->value("mainwindow.width").value(), config->value("mainwindow.height").value()); + titleSuffix = QString::fromStdString(config->value("mainwindow.title").value()); + setWindowTitle(tr("smolbote")); + if(config->value("mainwindow.maximized").value()) + showMaximized(); + else + show(); + + createMenuBar(); + auto *navigationToolBar = new NavigationBar(config->section("navigation"), this); + navigationToolBar->setMovable(config->value("navigation.movable").value()); + addToolBar(Qt::TopToolBarArea, navigationToolBar); + navigationToolBar->connectWebView(nullptr); + + setCentralWidget(mdiArea); + mdiArea->setFocus(); + + connect(mdiArea, &QMdiArea::subWindowActivated, this, [this, navigationToolBar](QMdiSubWindow *window) { + disconnect(titleChangedConnection); + disconnect(navigationBarConnection); + + auto *w = qobject_cast(window); + if(w != nullptr) { + setWindowTitle(w->windowTitle() + titleSuffix); + titleChangedConnection = connect(w, &Window::windowTitleChanged, this, [this](const QString &title) { + this->setWindowTitle(title + titleSuffix); + }); - // 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)); + navigationToolBar->connectWebView(w->currentView()); + navigationBarConnection = connect(w, &Window::currentViewChanged, navigationToolBar, &NavigationBar::connectWebView); + } }); - connect(tabBar, &TabBar::currentTabChanged, this, &MainWindow::handleTabChanged); - // loading bar - ui->statusBar->addPermanentWidget(m_progressBar); - - // search box - m_searchBox = new SearchForm(this); - ui->statusBar->addWidget(m_searchBox); - m_searchBox->setVisible(false); - - resize(m_config->value("browser.window.width").value(), m_config->value("browser.window.height").value()); - if(m_config->value("browser.window.maximized").value()) { - showMaximized(); - } + auto *tileShortcut = new QShortcut(QKeySequence(config->value("mainwindow.shortcuts.tileWindows").value().c_str()), this); + connect(tileShortcut, &QShortcut::activated, this, [this]() { + mdiArea->tileSubWindows(); + }); } 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; + disconnect(titleChangedConnection); + disconnect(navigationBarConnection); } -void MainWindow::addTabbedDock(Qt::DockWidgetArea area, QWidget *widget) +void MainWindow::createMenuBar() { - // 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; - } + auto *smolboteMenu = menuBar()->addMenu(qApp->applicationDisplayName()); + smolboteMenu->addAction(tr("New tab"), this, [this]() { + createTab(QUrl::fromUserInput("about:blank")); + }, + QKeySequence(m_config->value("mainwindow.shortcuts.newTab").value().c_str())); - if(dockWidgetArea(w) == area) { - areaDockWidgets.append(w); - } - } + smolboteMenu->addAction(tr("New tab group"), this, [this]() { + createSubWindow(QUrl::fromUserInput("about:blank")); + }, + QKeySequence(m_config->value("mainwindow.shortcuts.newGroup").value().c_str())); + smolboteMenu->addAction(tr("New window"))->setEnabled(false); - // create a dock widget - QDockWidget *dock = new QDockWidget(widget->windowTitle(), this); - dock->setAttribute(Qt::WA_DeleteOnClose, true); + smolboteMenu->addSeparator(); - // 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); + smolboteMenu->addAction(tr("About"), this, [this]() { + auto *dlg = new AboutDialog(this); + dlg->exec(); + }, + QKeySequence(m_config->value("mainwindow.shortcuts.about").value().c_str())); + smolboteMenu->addAction(tr("About Qt"), qApp, &QApplication::aboutQt); - // 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); - } -} + smolboteMenu->addSeparator(); -void MainWindow::newTab(const QUrl &url) -{ - if(!m_tabBarAdded) { - m_tabBarAdded = true; - ui->mainToolBar->addWidget(tabBar); - } - tabBar->addTab(createWebView(url, m_profile.get(), this)); -} + smolboteMenu->addAction(tr("Quit"), qApp, &QApplication::quit, + QKeySequence(m_config->value("mainwindow.shortcuts.quit").value().c_str())); -MainWindow *MainWindow::newWindow(const QUrl &url) -{ - auto *instance = dynamic_cast(QApplication::instance()); - return instance->createSession(m_profile->storageName(), true, QStringList(url.toString())); + toolsMenu = menuBar()->addMenu(tr("Tools")); } -void MainWindow::closeEvent(QCloseEvent *event) +void MainWindow::addAction(ActionLocation where, QAction *action) { - 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; - } + switch(where) { + case ToolsMenu: + toolsMenu->addAction(action); + break; + default: + QMainWindow::addAction(action); + break; } - QMainWindow::closeEvent(event); -} - -void MainWindow::about() -{ - auto *dlg = new AboutDialog(this); - dlg->exec(); } -void MainWindow::setProfile(std::shared_ptr profile) +void MainWindow::addDockWidget(Qt::DockWidgetArea area, QWidget *widget) { - Q_ASSERT(profile); - m_profile = profile; - tabBar->setProfile(profile.get()); - menuBar->profileAction()->setText(tr("Current profile: %1").arg(profile->name())); -} - -WebEngineProfile *MainWindow::profile() -{ - Q_ASSERT(m_profile); - return m_profile.get(); -} + QDockWidget *dock = new QDockWidget(widget->windowTitle(), this); + dock->setAttribute(Qt::WA_DeleteOnClose, true); + dock->setWidget(widget); -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); + connect(dock, &QDockWidget::visibilityChanged, [dock](bool visible) { + if(!visible && dock->widget()) { + dock->widget()->setParent(nullptr); } }); -} -void MainWindow::setDownloadsWidget(std::shared_ptr &widget) -{ - Q_ASSERT(widget); - m_downloadsWidget = widget; + QMainWindow::addDockWidget(area, dock); } -void MainWindow::toggleFullscreen() +void MainWindow::createTab(const QUrl &url) { - if(isFullScreen()) { - setWindowState(Qt::WindowMaximized | Qt::WindowActive); + auto *w = qobject_cast(mdiArea->currentSubWindow()); + if(w == nullptr) { + w = createSubWindow(url); } else { - setWindowState(Qt::WindowFullScreen | Qt::WindowActive); + w->addTab(url); } } -void MainWindow::handleTabChanged(WebView *view) +Window *MainWindow::createSubWindow(const QUrl &url) { - Q_CHECK_PTR(view); + auto *w = new Window(this); + mdiArea->addSubWindow(w); + w->showMaximized(); + w->setFocus(); - disconnect(titleChangedConnection); - disconnect(newBookmarkConnection); + w->addTab(url); - 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); - - m_addressBar->connectWebView(view); - - titleChangedConnection = connect(view, &WebView::titleChanged, this, &MainWindow::handleTitleUpdated); - newBookmarkConnection = connect(view, &WebView::newBookmark, this, [this](const QString &title, const QUrl &url) { - if(m_bookmarksWidget) { - auto *bookmark = m_bookmarksWidget->model()->createBookmark(nullptr); - bookmark->setText(0, title); - bookmark->setText(1, url.toString()); - } - }); - - m_progressBar->connectWebView(view); - - // update UI - this->handleTitleUpdated(view->title()); - centralWidget()->setFocus(); + return w; } -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) +void MainWindow::closeEvent(QCloseEvent *event) { - for(const Browser::Plugin &plugin : plugins) { - ProfileInterface *iProfilePlugin = qobject_cast(plugin.pointer); - if(iProfilePlugin) { - QWidget *w = iProfilePlugin->createWidget(m_profile.get(), this); - - menuBar->profileAction()->setEnabled(true); - connect(menuBar->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(); - } - }); + if(mdiArea->subWindowList().count() > 1) { + int choice = QMessageBox::question(this, tr("Close multiple subwindows?"), tr("Do you want to close all subwindows?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + if(choice == QMessageBox::No) { + event->ignore(); + return; } } + + mdiArea->closeAllSubWindows(); + if(mdiArea->currentSubWindow()) + event->ignore(); + else + event->accept(); } -- cgit v1.2.1