diff options
-rw-r--r-- | lib/web/profilemanager.cpp | 20 | ||||
-rw-r--r-- | lib/web/profilemanager.h | 1 | ||||
-rw-r--r-- | linux/makepkg/PKGBUILD | 2 | ||||
-rw-r--r-- | src/browser.cpp | 42 | ||||
-rw-r--r-- | src/browser.h | 8 | ||||
-rw-r--r-- | src/mainwindow/mainwindow.cpp | 130 | ||||
-rw-r--r-- | src/mainwindow/mainwindow.h | 17 | ||||
-rw-r--r-- | src/mainwindow/mainwindow.ui | 202 | ||||
-rw-r--r-- | src/mainwindow/menubar.cpp | 239 | ||||
-rw-r--r-- | src/mainwindow/menubar.h | 28 | ||||
-rw-r--r-- | src/mainwindow/widgets/menusearch.cpp | 17 | ||||
-rw-r--r-- | src/mainwindow/widgets/menusearch.h | 20 | ||||
-rw-r--r-- | src/mainwindow/widgets/navigationbar.cpp | 4 | ||||
-rw-r--r-- | src/meson.build | 6 | ||||
-rw-r--r-- | src/session/session.cpp | 4 | ||||
-rw-r--r-- | src/subwindow/subwindow.cpp | 38 | ||||
-rw-r--r-- | src/subwindow/subwindow.h | 3 | ||||
-rw-r--r-- | src/subwindow/tabwidget.cpp | 78 | ||||
-rw-r--r-- | src/subwindow/tabwidget.h | 5 |
19 files changed, 431 insertions, 433 deletions
diff --git a/lib/web/profilemanager.cpp b/lib/web/profilemanager.cpp index 14795cd..6e6281b 100644 --- a/lib/web/profilemanager.cpp +++ b/lib/web/profilemanager.cpp @@ -10,6 +10,8 @@ #include "webprofile.h" #include <QFileInfo> #include <QWebEngineSettings> +#include <QWidgetAction> +#include <QRadioButton> ProfileManager::ProfileManager(const QHash<QString, QString> &profileSection, QObject *parent) : QObject(parent) @@ -111,6 +113,24 @@ void ProfileManager::deleteProfile(const QString &id) } } +void ProfileManager::profilePickerMenu(QMenu *menu, WebProfile *current, std::function<void(WebProfile *)> callback) const +{ + for(const auto &profileData : m_profiles) { + WebProfile *profile = profileData.second->profile; + + auto *profileButton = new QRadioButton(profile->name(), menu); + profileButton->setChecked(profile == current); + + auto *action = new QWidgetAction(menu); + action->setDefaultWidget(profileButton); + connect(profileButton, &QRadioButton::clicked, profile, [profile, callback]() { + callback(profile); + }); + + menu->addAction(action); + } +} + QMenu *ProfileManager::createProfileMenu(std::function<void(WebProfile *)> callback, QWidget *parent) const { auto *menu = new QMenu(parent); diff --git a/lib/web/profilemanager.h b/lib/web/profilemanager.h index f5e33b9..e0040a3 100644 --- a/lib/web/profilemanager.h +++ b/lib/web/profilemanager.h @@ -31,6 +31,7 @@ public: WebProfile *loadProfile(const QString &path); void deleteProfile(const QString &id); + void profilePickerMenu(QMenu *menu, WebProfile *current, std::function<void(WebProfile *)> callback) const; QMenu *createProfileMenu(std::function<void(WebProfile *)> callback, QWidget *parent = nullptr) const; const QStringList idList() const; diff --git a/linux/makepkg/PKGBUILD b/linux/makepkg/PKGBUILD index cd5e8db..52537d1 100644 --- a/linux/makepkg/PKGBUILD +++ b/linux/makepkg/PKGBUILD @@ -57,7 +57,7 @@ build() { # b_pie: Build executables as position independent # b_lto: Use link time optimization meson --buildtype=plain --prefix=/usr/local --auto-features=disabled \ - -Db_pie=enabled -Db_lto=enabled -Dcpp_link_args="-fuse-ld=gold" \ + -Db_pie=true -Db_lto=true -Dcpp_link_args="-fuse-ld=gold" \ -DPlasma=enabled -Dmanpage=enabled \ $srcdir/build diff --git a/src/browser.cpp b/src/browser.cpp index 18ccc92..0422a4e 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -17,7 +17,6 @@ #include "mainwindow/mainwindow.h" #include "profilemanager.h" #include "subwindow/subwindow.h" -#include "ui_mainwindow.h" #include "util.h" #include "webengine/filter.h" #include "webengine/urlinterceptor.h" @@ -34,6 +33,7 @@ #include <QVersionNumber> #include <plugininterface.h> #include <version.h> +#include "mainwindow/menubar.h" Browser::Browser(int &argc, char *argv[], bool allowSecondary) : SingleApplication(argc, argv, allowSecondary, SingleApplication::User | SingleApplication::SecondaryNotification | SingleApplication::ExcludeAppVersion) @@ -195,38 +195,21 @@ void Browser::setup(QVector<QPluginLoader *> plugins) timer->start(5 * 60 * 1000); } +void Browser::showWidget(QWidget *widget, MainWindow *where) const +{ + bool wasVisible = widget->isVisible(); + for(MainWindow *w : qAsConst(m_windows)) + w->removeDockWidget(widget); + + if(!wasVisible) + where->addDockWidget(Qt::RightDockWidgetArea, widget); +} + MainWindow *Browser::createWindow() { // the window will delete itself when it closes, so we don't need to delete it auto *window = new MainWindow(m_config); connect(window->addressBar, &AddressBar::complete, m_bookmarks.get(), &BookmarksWidget::search); - connect(window, &MainWindow::createBookmark, m_bookmarks.get(), &BookmarksWidget::addBookmark); - - m_config->setShortcut(window->ui->actionBookmarks, "bookmarks.shortcut"); - connect(window->ui->actionBookmarks, &QAction::triggered, window, [this, window]() { - bool wasVisible = m_bookmarks->isVisible(); - for(MainWindow *w : qAsConst(m_windows)) { - w->removeDockWidget(m_bookmarks.get()); - } - if(!wasVisible) { - window->addDockWidget(Qt::RightDockWidgetArea, m_bookmarks.get()); - } - }); - - m_config->setShortcut(window->ui->actionDownloads, "downloads.shortcut"); - connect(window->ui->actionDownloads, &QAction::triggered, window, [this, window]() { - bool wasVisible = m_downloads->isVisible(); - for(MainWindow *w : qAsConst(m_windows)) { - w->removeDockWidget(m_downloads.get()); - } - if(!wasVisible) { - window->addDockWidget(Qt::RightDockWidgetArea, m_downloads.get()); - } - }); - - connect(window->ui->actionAddPlugin, &QAction::triggered, this, [this]() { - this->addPlugin(QFileDialog::getOpenFileName(nullptr, tr("Add Plugin"), QDir::homePath(), tr("Plugins (*.so)"))); - }); for(auto *info : m_plugins) { addPluginTo(info, window); @@ -243,7 +226,8 @@ MainWindow *Browser::createWindow() void Browser::addPluginTo(PluginInfo *info, MainWindow *window) { QPluginLoader *loader = info->loader; - auto *pluginMenu = window->ui->menuTools->addMenu(loader->metaData().value("MetaData").toObject().value("name").toString()); + auto *pluginMenu = new QMenu(loader->metaData().value("MetaData").toObject().value("name").toString()); + window->m_menuBar->insertPlugin(pluginMenu); info->menus.append(pluginMenu); auto *aboutAction = pluginMenu->addAction(tr("About")); diff --git a/src/browser.h b/src/browser.h index f5c63f8..53ee521 100644 --- a/src/browser.h +++ b/src/browser.h @@ -58,7 +58,15 @@ public: return qAsConst(m_windows); } + BookmarksWidget *bookmarks() const { + return m_bookmarks.get(); + } + DownloadsWidget *downloads() const { + return m_downloads.get(); + } + public slots: + void showWidget(QWidget *widget, MainWindow *where) const; MainWindow *createWindow(); private: diff --git a/src/mainwindow/mainwindow.cpp b/src/mainwindow/mainwindow.cpp index 1544e79..ea024c5 100644 --- a/src/mainwindow/mainwindow.cpp +++ b/src/mainwindow/mainwindow.cpp @@ -11,11 +11,11 @@ #include "browser.h" #include "config.h" #include "configuration.h" +#include "menubar.h" #include "profilemanager.h" #include "session/session.h" #include "session/sessiondialog.h" #include "subwindow/subwindow.h" -#include "ui_mainwindow.h" #include "webengine/webview.h" #include "webprofile.h" #include "widgets/dockwidget.h" @@ -31,9 +31,6 @@ #include <QMdiSubWindow> #include <QMenuBar> #include <QMessageBox> -#include <QPrintDialog> -#include <QPrinter> -#include <QPrinterInfo> #include <QShortcut> #include <QStatusBar> #include <QToolBar> @@ -71,12 +68,13 @@ inline QDialog *createDevToolsDialog(QWebEnginePage *page) MainWindow::MainWindow(const std::unique_ptr<Configuration> &config, QWidget *parent) : QMainWindow(parent) - , ui(new Ui::MainWindow) + , configuration(config.get()) , mdiArea(new QMdiArea(this)) { Q_ASSERT(config); - ui->setupUi(this); + m_menuBar = new MenuBar(config.get(), this); + this->setMenuBar(m_menuBar); #ifdef CONFIG_PLASMA_BLUR setAttribute(Qt::WA_TranslucentBackground, true); @@ -91,98 +89,6 @@ MainWindow::MainWindow(const std::unique_ptr<Configuration> &config, QWidget *pa } show(); - // connect smolbote menu - { - connect(ui->actionNewSubwindow, &QAction::triggered, this, [this, &config]() { - auto *profile = WebProfile::defaultProfile(); - auto *window = createSubWindow(config.get(), profile); - window->addTab(profile->newtab(), profile); - }); - config->setShortcut(ui->actionNewSubwindow, "mainwindow.shortcuts.newGroup"); - - connect(ui->actionNewWindow, &QAction::triggered, this, []() { - auto *browser = qobject_cast<Browser *>(qApp); - if(browser) - browser->createWindow(); - }); - config->setShortcut(ui->actionNewWindow, "mainwindow.shortcuts.newWindow"); - - connect(ui->actionAbout, &QAction::triggered, qobject_cast<Browser *>(qApp), &Browser::about); - config->setShortcut(ui->actionAbout, "mainwindow.shortcuts.about"); - - connect(ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt); - - connect(ui->actionQuit, &QAction::triggered, qApp, &QApplication::quit); - config->setShortcut(ui->actionQuit, "mainwindow.shortcuts.quit"); - } - - // connect session menu - { - const QString sessionPath = config->value<QString>("browser.session.path").value(); - connect(ui->actionSaveSession, &QAction::triggered, this, [this, sessionPath]() { - const QString filename = QFileDialog::getSaveFileName(this, tr("Save Session"), sessionPath, tr("JSON (*.json)")); - QFile output(filename); - if(output.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { - auto *browser = qobject_cast<Browser *>(qApp); - auto data = Session::_session(browser->windows()); - output.write(QJsonDocument(data).toJson()); - output.close(); - } - }); - - connect(ui->actionLoadSession, &QAction::triggered, this, [this]() { - auto *sessionDialog = new SessionDialog(this); - sessionDialog->exec(); - }); - } - - // connect window menu - { - connect(ui->actionTileSubwindows, &QAction::triggered, mdiArea, &QMdiArea::tileSubWindows); - config->setShortcut(ui->actionTileSubwindows, "mainwindow.shortcuts.tileWindows"); - - connect(ui->actionCascadeSubwindows, &QAction::triggered, mdiArea, &QMdiArea::cascadeSubWindows); - config->setShortcut(ui->actionCascadeSubwindows, "mainwindow.shortcuts.cascadeWindows"); - } - - // connect page menu - { - connect(ui->actionBookmarkPage, &QAction::triggered, this, [this]() { - if(currentView != nullptr) - emit createBookmark(currentView->title(), currentView->url().toString()); - }); - connect(ui->actionSavePage, &QAction::triggered, this, [this]() { - if(currentView != nullptr) - currentView->triggerPageAction(QWebEnginePage::SavePage); - }); - connect(ui->actionPrintPage, &QAction::triggered, this, [this]() { - if(currentView != nullptr) { - auto *printer = new QPrinter(QPrinterInfo::defaultPrinter()); - QPrintDialog dlg(printer, this); - if(dlg.exec() == QDialog::Accepted) { - currentView->page()->print(printer, [printer](bool success) { - Q_UNUSED(success); - delete printer; - }); - } - } - }); - connect(ui->actionPrintPageToPdf, &QAction::triggered, this, [this]() { - if(currentView != nullptr) { - const QString path = QFileDialog::getSaveFileName(this, tr("Print to PDF"), QDir::homePath(), tr("PDF files (*.pdf)")); - currentView->page()->printToPdf(path); - } - }); - - connect(ui->actionDeveloperTools, &QAction::triggered, this, [this]() { - if(currentView != nullptr) - createDevToolsDialog(currentView->page())->show(); - }); - - pageLoadProfileMenu = ui->menuPage->addMenu(tr("Load Profile")); - connect(pageLoadProfileMenu, &QMenu::aboutToShow, this, &MainWindow::updatePageLoadProfileMenu); - } - // current subwindow shortcut { QAction *subwindowMenuAction = new QAction(this); @@ -221,16 +127,13 @@ MainWindow::MainWindow(const std::unique_ptr<Configuration> &config, QWidget *pa disconnect(viewChangedConnection); disconnect(searchBoxConnection); disconnect(statusBarConnection); - ui->actionCurrentSubwindow->setMenu(nullptr); auto *w = qobject_cast<SubWindow *>(window); if(w == nullptr) { // no current subwindow, clear everything setView(nullptr); - ui->actionCurrentSubwindow->setMenu(nullptr); } else { setView(w->currentView()); - ui->actionCurrentSubwindow->setMenu(w->systemMenu()); viewChangedConnection = connect(w, &SubWindow::currentViewChanged, this, &MainWindow::setView); statusBarConnection = connect(w, &SubWindow::showStatusMessage, statusBar(), &QStatusBar::showMessage); } @@ -340,7 +243,7 @@ SubWindow *MainWindow::currentSubWindow() const return qobject_cast<SubWindow *>(mdiArea->currentSubWindow()); } -SubWindow *MainWindow::createSubWindow(const Configuration *config, WebProfile *profile) +SubWindow *MainWindow::createSubWindow(WebProfile *profile, bool openProfileNewtab) { bool shouldMaximize = true; // if there is a current window, use its maximize state @@ -348,7 +251,8 @@ SubWindow *MainWindow::createSubWindow(const Configuration *config, WebProfile * shouldMaximize = currentWindow->isMaximized(); } - auto *w = new SubWindow(config, this); + auto *w = new SubWindow(configuration, this); + w->setProfile(profile); mdiArea->addSubWindow(w); if(shouldMaximize) @@ -357,6 +261,10 @@ SubWindow *MainWindow::createSubWindow(const Configuration *config, WebProfile * w->show(); w->setFocus(); + + if(openProfileNewtab) + w->addTab(w->profile()->newtab()); + return w; } @@ -384,22 +292,6 @@ void MainWindow::setView(WebView *view) searchBox->setView(view); } -void MainWindow::updatePageLoadProfileMenu() -{ - Q_CHECK_PTR(pageLoadProfileMenu); - pageLoadProfileMenu->clear(); - - if(currentView == nullptr) - return; - - auto *profileManager = dynamic_cast<Browser *>(qApp)->getProfileManager(); - pageLoadProfileMenu->addActions(profileManager->createProfileMenu([this](WebProfile *profile) { - this->currentView->setProfile(profile); - }, - this) - ->actions()); -} - void MainWindow::closeEvent(QCloseEvent *event) { if(mdiArea->subWindowList().count() > 1) { diff --git a/src/mainwindow/mainwindow.h b/src/mainwindow/mainwindow.h index de77540..44ee633 100644 --- a/src/mainwindow/mainwindow.h +++ b/src/mainwindow/mainwindow.h @@ -22,15 +22,11 @@ class SearchForm; class WebView; class NavigationBar; class WebProfile; - -namespace Ui -{ -class MainWindow; -} - +class MenuBar; class MainWindow : public QMainWindow { friend class Browser; + friend class MenuBar; Q_OBJECT @@ -49,22 +45,19 @@ public: const QVector<SubWindow *> subWindows() const; SubWindow *currentSubWindow() const; -signals: - void createBookmark(const QString &title, const QString &url); - public slots: void createTab(const QUrl &url); - SubWindow *createSubWindow(const Configuration *config, WebProfile *profile); + SubWindow *createSubWindow(WebProfile *profile = nullptr, bool openProfileNewtab = false); private slots: void setView(WebView *view); - void updatePageLoadProfileMenu(); protected: void closeEvent(QCloseEvent *event) override; private: - Ui::MainWindow *ui; + const Configuration *configuration = nullptr; + MenuBar *m_menuBar = nullptr; QMenu *toolsMenu = nullptr; QMenu *pageLoadProfileMenu = nullptr; diff --git a/src/mainwindow/mainwindow.ui b/src/mainwindow/mainwindow.ui deleted file mode 100644 index 19cecbb..0000000 --- a/src/mainwindow/mainwindow.ui +++ /dev/null @@ -1,202 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>MainWindow</class> - <widget class="QMainWindow" name="MainWindow"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>800</width> - <height>600</height> - </rect> - </property> - <property name="windowTitle"> - <string>MainWindow</string> - </property> - <widget class="QWidget" name="centralwidget"/> - <widget class="QMenuBar" name="menubar"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>800</width> - <height>30</height> - </rect> - </property> - <widget class="QMenu" name="menusmolbote"> - <property name="title"> - <string>s&molbote</string> - </property> - <addaction name="actionNewSubwindow"/> - <addaction name="actionNewWindow"/> - <addaction name="separator"/> - <addaction name="actionAbout"/> - <addaction name="actionAboutQt"/> - <addaction name="separator"/> - <addaction name="actionQuit"/> - </widget> - <widget class="QMenu" name="menuSession"> - <property name="title"> - <string>Sessio&n</string> - </property> - <addaction name="actionSaveSession"/> - <addaction name="actionLoadSession"/> - </widget> - <widget class="QMenu" name="menuSubWindow"> - <property name="title"> - <string>S&ubwindow</string> - </property> - <addaction name="actionTileSubwindows"/> - <addaction name="actionCascadeSubwindows"/> - <addaction name="separator"/> - <addaction name="actionCurrentSubwindow"/> - </widget> - <widget class="QMenu" name="menuTools"> - <property name="title"> - <string>Too&ls</string> - </property> - <addaction name="actionBookmarks"/> - <addaction name="actionDownloads"/> - <addaction name="separator"/> - <addaction name="actionAddPlugin"/> - <addaction name="separator"/> - </widget> - <widget class="QMenu" name="menuPage"> - <property name="title"> - <string>Pa&ge</string> - </property> - <addaction name="actionBookmarkPage"/> - <addaction name="actionSavePage"/> - <addaction name="actionPrintPage"/> - <addaction name="actionPrintPageToPdf"/> - <addaction name="separator"/> - <addaction name="actionDeveloperTools"/> - </widget> - <addaction name="menusmolbote"/> - <addaction name="menuSession"/> - <addaction name="menuSubWindow"/> - <addaction name="menuPage"/> - <addaction name="menuTools"/> - </widget> - <widget class="QStatusBar" name="statusbar"/> - <action name="actionNewSubwindow"> - <property name="text"> - <string>&New Subwindow</string> - </property> - </action> - <action name="actionNewWindow"> - <property name="icon"> - <iconset theme="window-new"/> - </property> - <property name="text"> - <string>New &Window</string> - </property> - </action> - <action name="actionAbout"> - <property name="icon"> - <iconset theme="help-about"/> - </property> - <property name="text"> - <string>&About</string> - </property> - </action> - <action name="actionAboutQt"> - <property name="text"> - <string>A&bout Qt</string> - </property> - </action> - <action name="actionQuit"> - <property name="icon"> - <iconset theme="application-exit"/> - </property> - <property name="text"> - <string>&Quit</string> - </property> - </action> - <action name="actionSaveSession"> - <property name="text"> - <string>&Save Session</string> - </property> - </action> - <action name="actionLoadSession"> - <property name="text"> - <string>&Load Session</string> - </property> - </action> - <action name="actionTileSubwindows"> - <property name="text"> - <string>&Tile Subwindows</string> - </property> - </action> - <action name="actionCascadeSubwindows"> - <property name="text"> - <string>&Cascade Subwindows</string> - </property> - </action> - <action name="actionCurrentSubwindow"> - <property name="text"> - <string>Current &Subwindow</string> - </property> - </action> - <action name="actionBookmarkPage"> - <property name="text"> - <string>&Create Bookmark</string> - </property> - </action> - <action name="actionSavePage"> - <property name="icon"> - <iconset theme="document-save"/> - </property> - <property name="text"> - <string>&Save Page</string> - </property> - </action> - <action name="actionPrintPage"> - <property name="icon"> - <iconset theme="document-print"/> - </property> - <property name="text"> - <string>&Print Page</string> - </property> - </action> - <action name="actionPrintPageToPdf"> - <property name="icon"> - <iconset theme="document-print"/> - </property> - <property name="text"> - <string>P&rint to PDF</string> - </property> - </action> - <action name="actionDeveloperTools"> - <property name="text"> - <string>&Developer Tools</string> - </property> - </action> - <action name="actionBookmarks"> - <property name="icon"> - <iconset theme="bookmarks"/> - </property> - <property name="text"> - <string>&Bookmarks</string> - </property> - </action> - <action name="actionDownloads"> - <property name="icon"> - <iconset theme="download"/> - </property> - <property name="text"> - <string>&Downloads</string> - </property> - </action> - <action name="actionAddPlugin"> - <property name="icon"> - <iconset theme="plugins"/> - </property> - <property name="text"> - <string>&Add Plugin</string> - </property> - </action> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/mainwindow/menubar.cpp b/src/mainwindow/menubar.cpp new file mode 100644 index 0000000..0429ffd --- /dev/null +++ b/src/mainwindow/menubar.cpp @@ -0,0 +1,239 @@ +/* + * 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: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "menubar.h" +#include "bookmarkswidget.h" +#include "browser.h" +#include "configuration.h" +#include "downloadswidget.h" +#include "mainwindow.h" +#include "profilemanager.h" +#include "session/sessiondialog.h" +#include "subwindow/subwindow.h" +#include "webengine/webview.h" +#include "widgets/menusearch.h" +#include <QApplication> +#include <QDir> +#include <QFileDialog> +#include <QLineEdit> +#include <QMdiArea> +#include <QPrintDialog> +#include <QPrinter> +#include <QPrinterInfo> +#include <QWidgetAction> + +MenuBar::MenuBar(const Configuration *config, MainWindow *parent) + : QMenuBar(parent) +{ + auto *browser = qobject_cast<Browser *>(qApp); + Q_CHECK_PTR(browser); + + smolbote = this->addMenu(qApp->applicationName()); + { + auto *findMenu = smolbote->addMenu(tr("Find in menus")); + + auto *findWidget = new QWidgetAction(this); + auto *find_lineEdit = new MenuSearch(this); + findWidget->setDefaultWidget(find_lineEdit); + findMenu->addAction(findWidget); + + connect(findMenu, &QMenu::aboutToShow, [findMenu, find_lineEdit]() { + find_lineEdit->clear(); + const auto actions = findMenu->actions(); + for(int i = 1; i < actions.length(); i++) + findMenu->removeAction(actions.at(i)); + find_lineEdit->setFocus(); + }); + + connect(find_lineEdit, &QLineEdit::textEdited, [this, findMenu](const QString &text) { + // clear menu + const auto actions = findMenu->actions(); + for(int i = 1; i < actions.length(); i++) + findMenu->removeAction(actions.at(i)); + + if(text.isEmpty()) + return; + + // findChildren + for(QAction *a : this->findChildren<QAction *>()) { + if(a->text().contains(text)) + findMenu->addAction(a); + } + }); + + smolbote->addSeparator(); + + const QString sessionPath = config->value<QString>("browser.session.path").value(); + smolbote->addAction(tr("Save Session"), parent, [parent, sessionPath]() { + const QString filename = QFileDialog::getSaveFileName(parent, tr("Save Session"), sessionPath, tr("JSON (*.json)")); + QFile output(filename); + if(output.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { + auto *browser = qobject_cast<Browser *>(qApp); + auto data = Session::_session(browser->windows()); + output.write(QJsonDocument(data).toJson()); + output.close(); + } + }); + + smolbote->addAction(tr("Open Session"), parent, [parent]() { + auto *sessionDialog = new SessionDialog(parent); + sessionDialog->exec(); + }); + + smolbote->addSeparator(); + auto *actionBookmarks = smolbote->addAction(tr("Bookmarks"), browser, [browser, parent]() { + browser->showWidget(browser->bookmarks(), parent); + }); + config->setShortcut(actionBookmarks, "bookmarks.shortcut"); + + auto *actionDownloads = smolbote->addAction(tr("Downloads"), browser, [browser, parent]() { + browser->showWidget(browser->downloads(), parent); + }); + config->setShortcut(actionDownloads, "downloads.shortcut"); + + smolbote->addSeparator(); + smolbote->addAction(tr("Load Plugin"), browser, [browser]() { + const QString path = QFileDialog::getOpenFileName(nullptr, tr("Select Plugin"), QDir::homePath(), tr("Plugins (*.so)")); + browser->addPlugin(path); + }); + + pluginInsertLocation = smolbote->addSeparator(); + + auto *actionAbout = smolbote->addAction(tr("About"), browser, &Browser::about); + config->setShortcut(actionAbout, "mainwindow.shortcuts.about"); + + smolbote->addAction(tr("Help")); + + //smolbote->addAction(tr("Check for updates")); + + smolbote->addSeparator(); + + auto *actionQuit = smolbote->addAction(tr("Quit"), qApp, &QApplication::quit); + config->setShortcut(actionQuit, "mainwindow.shortcuts.quit"); + } + + auto *window = this->addMenu(tr("Window")); + { + auto *actionNewWindow = window->addAction(tr("New Window"), browser, &Browser::createWindow); + config->setShortcut(actionNewWindow, "mainwindow.shortcuts.newWindow"); + + auto *actionNewSubwindow = window->addAction(tr("New Subwindow"), parent, [parent]() { + parent->createSubWindow(nullptr, true); + }); + config->setShortcut(actionNewSubwindow, "mainwindow.shortcuts.newGroup"); + + window->addSeparator(); + + auto *actionTileSubwindows = window->addAction(tr("Tile Subwindows"), parent->mdiArea, &QMdiArea::tileSubWindows); + config->setShortcut(actionTileSubwindows, "mainwindow.shortcuts.tileWindows"); + + auto *actionCascadeSubwindows = window->addAction(tr("Cascade Subwindows"), parent->mdiArea, &QMdiArea::cascadeSubWindows); + config->setShortcut(actionCascadeSubwindows, "mainwindow.shortcuts.cascadeWindows"); + } + + auto *subwindow = this->addMenu(tr("Subwindow")); + { + auto *actionNewTab = subwindow->addAction(tr("New Tab"), parent, [parent]() { + auto *_subwindow = parent->currentSubWindow(); + if(_subwindow != nullptr) { + const int index = _subwindow->addTab(); + _subwindow->setCurrentTab(index); + } + }); + config->setShortcut(actionNewTab, "subwindow.shortcuts.new"); + + subwindow->addSeparator(); + + subwindow->addAction(tr("Restore last tab"), parent, [parent]() { + auto *_subwindow = parent->currentSubWindow(); + if(_subwindow != nullptr) { + const int index = _subwindow->restoreLastTab(); + _subwindow->setCurrentTab(index); + } + }); + + auto *restoreTabsMenu = subwindow->addMenu(tr("Restore previous tab")); + connect(restoreTabsMenu, &QMenu::aboutToShow, parent, [parent, restoreTabsMenu]() { + restoreTabsMenu->clear(); + auto *_subwindow = parent->currentSubWindow(); + if(_subwindow != nullptr) { + _subwindow->restoreTabMenu(restoreTabsMenu); + } + }); + + subwindow->addSeparator(); + + auto *subwindowProfile = subwindow->addMenu(tr("Subwindow Profile")); + connect(subwindowProfile, &QMenu::aboutToShow, subwindowProfile, [=]() { + subwindowProfile->clear(); + + auto *_subwindow = parent->currentSubWindow(); + if(_subwindow != nullptr) { + browser->getProfileManager()->profilePickerMenu(subwindowProfile, _subwindow->profile(), [_subwindow](WebProfile *profile) { + _subwindow->setProfile(profile); + }); + } + }); + } + + auto *page = this->addMenu(tr("Page")); + { + page->addAction(tr("Create Bookmark"), parent, [browser, parent]() { + if(parent->currentView != nullptr) + browser->bookmarks()->addBookmark(parent->currentView->title(), parent->currentView->url().toString()); + }); + + page->addSeparator(); + + page->addAction(tr("Save"), parent, [parent]() { + if(parent->currentView != nullptr) + parent->currentView->triggerPageAction(QWebEnginePage::SavePage); + }); + page->addAction(tr("Print"), parent, [parent]() { + if(parent->currentView != nullptr) { + auto *printer = new QPrinter(QPrinterInfo::defaultPrinter()); + QPrintDialog dlg(printer, parent); + if(dlg.exec() == QDialog::Accepted) { + parent->currentView->page()->print(printer, [printer](bool success) { + Q_UNUSED(success); + delete printer; + }); + } + } + }); + + page->addAction(tr("Print to PDF"), parent, [parent]() { + if(parent->currentView != nullptr) { + const QString path = QFileDialog::getSaveFileName(parent, tr("Print to PDF"), QDir::homePath(), tr("PDF files (*.pdf)")); + parent->currentView->page()->printToPdf(path); + } + }); + + page->addSeparator(); + + auto pageProfile = page->addMenu(tr("Page Profile")); + connect(pageProfile, &QMenu::aboutToShow, pageProfile, [=]() { + pageProfile->clear(); + + if(parent->currentView != nullptr) { + browser->getProfileManager()->profilePickerMenu(pageProfile, parent->currentView->profile(), [parent](WebProfile *profile) { + parent->currentView->setProfile(profile); + }); + } + }); + + page->addSeparator(); + page->addAction(tr("Developer Tools")); + page->addAction(tr("View Source")); + } +} + +QAction *MenuBar::insertPlugin(QMenu *menu) +{ + return smolbote->insertMenu(pluginInsertLocation, menu); +} diff --git a/src/mainwindow/menubar.h b/src/mainwindow/menubar.h new file mode 100644 index 0000000..38b1286 --- /dev/null +++ b/src/mainwindow/menubar.h @@ -0,0 +1,28 @@ +/* + * 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: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_MENUBAR_H +#define SMOLBOTE_MENUBAR_H + +#include <QMenuBar> + +class Configuration; +class MainWindow; +class MenuBar : public QMenuBar +{ +public: + MenuBar(const Configuration *config, MainWindow *parent = nullptr); + + QAction *insertPlugin(QMenu *menu); + +private: + QMenu *smolbote = nullptr; + QAction *pluginInsertLocation = nullptr; +}; + +#endif // SMOLBOTE_MENUBAR_H diff --git a/src/mainwindow/widgets/menusearch.cpp b/src/mainwindow/widgets/menusearch.cpp new file mode 100644 index 0000000..2905d6d --- /dev/null +++ b/src/mainwindow/widgets/menusearch.cpp @@ -0,0 +1,17 @@ +/* + * 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: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#include "menusearch.h" + +MenuSearch::MenuSearch(QWidget *parent) + : QLineEdit(parent) +{ + setMinimumWidth(300); + setPlaceholderText(tr("Find...")); + setClearButtonEnabled(true); +} diff --git a/src/mainwindow/widgets/menusearch.h b/src/mainwindow/widgets/menusearch.h new file mode 100644 index 0000000..e20604c --- /dev/null +++ b/src/mainwindow/widgets/menusearch.h @@ -0,0 +1,20 @@ +/* + * 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: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote + * + * SPDX-License-Identifier: GPL-3.0 + */ + +#ifndef SMOLBOTE_MENUSEARCH_H +#define SMOLBOTE_MENUSEARCH_H + +#include <QLineEdit> + +class MenuSearch : public QLineEdit +{ +public: + MenuSearch(QWidget *parent = nullptr); +}; + +#endif // SMOLBOTE_MENUSEARCH_H diff --git a/src/mainwindow/widgets/navigationbar.cpp b/src/mainwindow/widgets/navigationbar.cpp index 61d17fa..c56d342 100644 --- a/src/mainwindow/widgets/navigationbar.cpp +++ b/src/mainwindow/widgets/navigationbar.cpp @@ -7,8 +7,9 @@ */ #include "navigationbar.h" -#include "urllineedit.h" #include "configuration.h" +#include "urllineedit.h" +#include "util.h" #include "webengine/webview.h" #include <QHBoxLayout> #include <QMenu> @@ -17,7 +18,6 @@ #include <QToolBar> #include <QToolButton> #include <QWebEngineHistory> -#include "util.h" NavigationBar::NavigationBar(const Configuration *config, QWidget *parent) : QToolBar(parent) diff --git a/src/meson.build b/src/meson.build index 0ad0166..7dfba88 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,11 +1,11 @@ # poi poi_moc = qt5.preprocess( moc_headers: ['browser.h', - 'mainwindow/mainwindow.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h', + 'mainwindow/mainwindow.h', 'mainwindow/menubar.h', 'mainwindow/widgets/dockwidget.h', 'mainwindow/widgets/menusearch.h', 'mainwindow/widgets/navigationbar.h', 'mainwindow/widgets/searchform.h', 'session/sessiondialog.h', 'session/sessionform.h', 'subwindow/subwindow.h', 'subwindow/tabwidget.h', 'webengine/filter.h', 'webengine/urlinterceptor.h', 'webengine/webpage.h', 'webengine/webview.h'], - ui_files: ['mainwindow/mainwindow.ui', 'mainwindow/widgets/searchform.ui', 'session/sessiondialog.ui', 'session/sessionform.ui'], + ui_files: ['mainwindow/widgets/searchform.ui', 'session/sessiondialog.ui', 'session/sessionform.ui'], qresources: '../data/resources.qrc', rcc_extra_arguments: ['--format-version=1'], dependencies: dep_qt5 @@ -30,7 +30,9 @@ poi = executable(get_option('poiName'), install: true, 'util.cpp', 'util.h', 'mainwindow/mainwindow.cpp', + 'mainwindow/menubar.cpp', 'mainwindow/widgets/dockwidget.cpp', + 'mainwindow/widgets/menusearch.cpp', 'mainwindow/widgets/navigationbar.cpp', 'mainwindow/widgets/searchform.cpp', diff --git a/src/session/session.cpp b/src/session/session.cpp index 10aca4e..f7d372b 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -150,7 +150,7 @@ void Session::restoreSession(const QJsonObject &sessionData) subwindow = window->currentSubWindow(); } else { window = browser->createWindow(); - subwindow = window->createSubWindow(browser->getConfiguration(), profileManager->profile(subwindowData.toObject()["profile"].toString())); + subwindow = window->createSubWindow(profileManager->profile(subwindowData.toObject()["profile"].toString())); } Q_CHECK_PTR(window); @@ -166,7 +166,7 @@ void Session::restoreSession(const QJsonObject &sessionData) auto *window = browser->createWindow(); for(const auto subwindowData : windowData.toObject()["subwindows"].toArray()) { - auto *subwindow = window->createSubWindow(browser->getConfiguration(), profileManager->profile(subwindowData.toObject()["profile"].toString())); + auto *subwindow = window->createSubWindow(profileManager->profile(subwindowData.toObject()["profile"].toString())); for(const auto tabData : subwindowData.toObject()["tabs"].toArray()) { auto *view = subwindow->view(subwindow->addTab()); diff --git a/src/subwindow/subwindow.cpp b/src/subwindow/subwindow.cpp index 0844f1f..4beba49 100644 --- a/src/subwindow/subwindow.cpp +++ b/src/subwindow/subwindow.cpp @@ -61,18 +61,6 @@ SubWindow::SubWindow(const Configuration *config, QWidget *parent, Qt::WindowFla menu->insertSeparator(firstAction); } - // new tab button - auto *newTab_button = new QToolButton(this); - newTab_button->setIcon(style()->standardIcon(QStyle::SP_FileIcon)); - newTab_button->setToolTip(tr("Add tab")); - newTab_button->setShortcut(QKeySequence(config->value<QString>("subwindow.shortcuts.new").value())); - connect(newTab_button, &QToolButton::clicked, this, [=]() { - auto index = addTab(WebProfile::defaultProfile()->newtab()); - tabWidget->setCurrentIndex(index); - }); - newTab_button->setMenu(tabWidget->createTabMenu(newTab_button)); - tabWidget->setCornerWidget(newTab_button, Qt::TopRightCorner); - // general actions auto *closeTab_shortcut = new QShortcut(QKeySequence(config->value<QString>("subwindow.shortcuts.close").value()), this); connect(closeTab_shortcut, &QShortcut::activated, this, [=]() { @@ -159,8 +147,10 @@ int SubWindow::tabCount() const void SubWindow::setProfile(WebProfile *profile) { - if(profile == nullptr) + if(profile == nullptr) { + setProfile(WebProfile::defaultProfile()); return; + } this->m_profile = profile; for(int i = 0; i < tabWidget->count(); ++i) { @@ -178,13 +168,29 @@ int SubWindow::addTab(const QUrl &url, WebProfile *profile) { Q_CHECK_PTR(m_profile); - auto *view = new WebView((profile == nullptr) ? m_profile : profile, this); - if(!url.isEmpty()) + auto *_profile = (profile == nullptr) ? m_profile : profile; + + auto *view = new WebView(_profile, this); + if(url.isEmpty()) + view->load(_profile->newtab()); + else view->load(url); + return tabWidget->addTab(view); } void SubWindow::setCurrentTab(int index) { - tabWidget->setCurrentIndex(index); + if(index > 0) + tabWidget->setCurrentIndex(index); +} + +int SubWindow::restoreLastTab() +{ + return tabWidget->restoreLastTab(); +} + +void SubWindow::restoreTabMenu(QMenu *menu) +{ + tabWidget->restoreTabMenu(menu); } diff --git a/src/subwindow/subwindow.h b/src/subwindow/subwindow.h index 3d70c98..1fc0097 100644 --- a/src/subwindow/subwindow.h +++ b/src/subwindow/subwindow.h @@ -40,6 +40,9 @@ public slots: int addTab(const QUrl &url = QUrl(), WebProfile *profile = nullptr); void setCurrentTab(int index); + int restoreLastTab(); + void restoreTabMenu(QMenu *menu); + private: WebProfile *m_profile; TabWidget *tabWidget; diff --git a/src/subwindow/tabwidget.cpp b/src/subwindow/tabwidget.cpp index 942a364..c635aee 100644 --- a/src/subwindow/tabwidget.cpp +++ b/src/subwindow/tabwidget.cpp @@ -31,7 +31,7 @@ TabWidget::TabWidget(QWidget *parent) setStyleSheet("QTabBar::tab { width: 200px; }"); setTabsClosable(true); - //setTabBarAutoHide(true); + setTabBarAutoHide(true); setElideMode(Qt::ElideRight); setMovable(true); @@ -75,51 +75,6 @@ TabWidget::~TabWidget() } } -QMenu *TabWidget::createTabMenu(QWidget *parent) -{ - auto *menu = new QMenu(parent); - - auto *reopenTabAction = menu->addAction(tr("Reopen last tab")); - connect(reopenTabAction, &QAction::triggered, this, [this]() { - if(!m_closedTabs.isEmpty()) { - TabInformation tab = m_closedTabs.takeLast(); - addTab(createViewFromInfo(tab, this)); - } - }); - - auto *tabHistoryMenu = menu->addMenu(tr("Tab History")); - connect(tabHistoryMenu, &QMenu::aboutToShow, this, [this, tabHistoryMenu]() { - tabHistoryMenu->clear(); - for(int i = 0; i < m_closedTabs.count(); ++i) { - auto *openAction = tabHistoryMenu->addAction(m_closedTabs.at(i).title); - - connect(openAction, &QAction::triggered, this, [this, i]() { - TabInformation tab = m_closedTabs.takeAt(i); - addTab(createViewFromInfo(tab, this)); - }); - } - - tabHistoryMenu->addSeparator(); - - auto *clearTabHistory = tabHistoryMenu->addAction(tr("Clear")); - connect(clearTabHistory, &QAction::triggered, this, [this]() { - m_closedTabs.clear(); - }); - }); - - connect(menu, &QMenu::aboutToShow, this, [this, reopenTabAction, tabHistoryMenu]() { - if(m_closedTabs.isEmpty()) { - reopenTabAction->setEnabled(false); - tabHistoryMenu->setEnabled(false); - } else { - reopenTabAction->setEnabled(true); - tabHistoryMenu->setEnabled(true); - } - }); - - return menu; -} - int TabWidget::addTab(WebView *view) { Q_ASSERT_X(view != nullptr, "TabWidget::addTab", "Tried to add null view"); @@ -165,6 +120,37 @@ void TabWidget::deleteTab(int index) parentWidget()->close(); } +int TabWidget::restoreLastTab() +{ + if(!m_closedTabs.isEmpty()) { + TabInformation tab = m_closedTabs.takeLast(); + return addTab(createViewFromInfo(tab, this)); + } + return -1; +} + +void TabWidget::restoreTabMenu(QMenu *menu) +{ + if(m_closedTabs.isEmpty()) + return; + + for(int i = 0; i < m_closedTabs.count(); ++i) { + auto *openAction = menu->addAction(m_closedTabs.at(i).title); + + connect(openAction, &QAction::triggered, this, [this, i]() { + TabInformation tab = m_closedTabs.takeAt(i); + addTab(createViewFromInfo(tab, this)); + }); + } + + menu->addSeparator(); + + auto *clearTabHistory = menu->addAction(tr("Clear")); + connect(clearTabHistory, &QAction::triggered, this, [this]() { + m_closedTabs.clear(); + }); +} + void TabWidget::contextMenuEvent(QContextMenuEvent *event) { // check if the context menu was called on a tab diff --git a/src/subwindow/tabwidget.h b/src/subwindow/tabwidget.h index 48690e8..ef1930d 100644 --- a/src/subwindow/tabwidget.h +++ b/src/subwindow/tabwidget.h @@ -34,12 +34,13 @@ public: explicit TabWidget(QWidget *parent = nullptr); ~TabWidget() override; - QMenu *createTabMenu(QWidget *parent = nullptr); - public slots: int addTab(WebView *view); void deleteTab(int index); + int restoreLastTab(); + void restoreTabMenu(QMenu *menu); + protected: void contextMenuEvent(QContextMenuEvent *event) override; void mousePressEvent(QMouseEvent *event) override; |