/* * 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/smolbote.hg * * SPDX-License-Identifier: GPL-3.0 */ #include "browser.h" #include "addressbar/addressbar.h" #include "mainwindow/mainwindow.h" #include "subwindow/subwindow.h" #include "webengine/urlinterceptor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include Browser::Browser(int &argc, char *argv[], bool allowSecondary) : SingleApplication(argc, argv, allowSecondary, SingleApplication::User | SingleApplication::SecondaryNotification | SingleApplication::ExcludeAppVersion) { setApplicationName(POI_NAME); setWindowIcon(QIcon(":/icon.svg")); setApplicationVersion(SMOLBOTE_VERSION); } Browser::~Browser() { if(m_bookmarks) m_bookmarks->save(); qDeleteAll(m_windows); m_windows.clear(); } void Browser::about() { auto *dlg = new AboutDialog; for(const Plugin &plugin : qAsConst(m_plugins)) { dlg->addPlugin(plugin.name, plugin.author, plugin.shortcut.toString()); } dlg->exec(); } QPair Browser::loadProfile(const QString &id) { WebProfile *profile = profileManager->loadProfile(id); connect(profile, &WebProfile::downloadRequested, m_downloads.get(), &DownloadsWidget::addDownload); profile->setRequestInterceptor(m_urlFilter.get()); return QPair(profileManager->id(profile), profile); } void Browser::setConfiguration(std::unique_ptr &config) { Q_ASSERT(config); m_config = std::move(config); } Configuration *Browser::getConfiguration() const { Q_ASSERT(m_config); return m_config.get(); } const ProfileManager *Browser::getProfileManager() const { return const_cast(ProfileManager::instance()); } void Browser::registerPlugin(const Plugin &plugin) { Q_ASSERT(m_config); auto *p = qobject_cast(plugin.instance); Q_CHECK_PTR(p); p->setBrowserInterface(this); m_plugins.append(plugin); } void Browser::setup(const QString &defaultProfile) { Q_ASSERT(m_config); ProfileManager::setInstance(new ProfileManager(m_config->section("profile"), this)); auto stylesheet = m_config->value("browser.stylesheet"); if(stylesheet) { QFile f(stylesheet.value()); if(f.open(QIODevice::ReadOnly)) { setStyleSheet(f.readAll()); f.close(); } } // downloads m_downloads = std::make_unique(m_config->value("downloads.path").value()); // url request filter m_urlFilter = std::make_unique(m_config); // cookie request filter // load profiles { const auto defaults = m_config->section("profile"); const QDir profilesDir(m_config->value("profile.path").value()); if(profilesDir.exists()) { const auto entries = profilesDir.entryInfoList({ "*.profile" }, QDir::Files | QDir::Readable, QDir::Time); for(const QFileInfo &f : entries) { loadProfile(f.absoluteFilePath()); } } // set default profile if(profileManager->profile(defaultProfile) == nullptr) { // if this profile has not been added, it doesn't have a path loadProfile(QString()); } WebProfile::setDefaultProfile(profileManager->profile(defaultProfile)); } // bookmarks m_bookmarks = std::make_shared(QString::fromStdString(m_config->value("bookmarks.path").value())); connect(m_bookmarks.get(), &BookmarksWidget::openUrl, this, [this](const QUrl &url) { m_windows.last()->createTab(url); }); auto *timer = new QTimer(this); connect(timer, &QTimer::timeout, m_bookmarks.get(), &BookmarksWidget::save); // 5min * 60sec * 1000ms timer->start(5*60*1000); } void Browser::createSession(const QJsonObject &object) { MainWindow *mainwindow = nullptr; if(m_windows.isEmpty()) mainwindow = createWindow(); else mainwindow = m_windows.last(); const QJsonArray subwindows = object.value("subwindows").toArray(); for(const QJsonValue &s : subwindows) { const QJsonObject subwindow = s.toObject(); const QString profileId = subwindow.value("profile").toString(); WebProfile *profile = profileManager->profile(profileId); if(profile == nullptr) profile = WebProfile::defaultProfile(); Q_CHECK_PTR(profile); SubWindow *window = nullptr; for(SubWindow *w : mainwindow->subWindows()) { if(w->profile() == profile) { window = w; break; } } if(window == nullptr) window = mainwindow->createSubWindow(m_config, profile); const QJsonArray tabs = subwindow.value("tabs").toArray(); if(tabs.isEmpty()) window->addTab(profile->newtab()); else { for(const QJsonValue &t : subwindow.value("tabs").toArray()) { const QJsonObject tab = t.toObject(); const QUrl url = QUrl::fromUserInput(tab.value("url").toString()); WebProfile *p = profileManager->profile(tab.value("profile").toString()); window->addTab(url, p); } } } } MainWindow *Browser::createWindow() { // the window will delete itself when it closes, so we don't need to delete it MainWindow *window = new MainWindow(m_config); connect(window->addressBar, &AddressBar::complete, m_bookmarks.get(), &BookmarksWidget::search); connect(window, &MainWindow::createBookmark, m_bookmarks.get(), &BookmarksWidget::addBookmark); auto *bookmarksAction = new QAction(tr("Bookmarks"), window); m_config->setShortcut(bookmarksAction, "bookmarks.shortcut"); connect(bookmarksAction, &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()); } }); window->addAction(MainWindow::ToolsMenu, bookmarksAction); auto *downloadsAction = new QAction(tr("Downloads"), window); m_config->setShortcut(downloadsAction, "downloads.shortcut"); connect(downloadsAction, &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()); } }); window->addAction(MainWindow::ToolsMenu, downloadsAction); for(const Plugin &p : qAsConst(m_plugins)) { auto *plugin = qobject_cast(p.instance); Q_CHECK_PTR(plugin); auto *pluginAction = new QAction(p.name, window); pluginAction->setShortcut(p.shortcut); connect(pluginAction, &QAction::triggered, window, [=]() { plugin->createWidget(window)->exec(); }); window->addAction(MainWindow::ToolsMenu, pluginAction); } m_windows.append(window); connect(window, &MainWindow::destroyed, this, [this, window]() { m_windows.removeOne(window); }); return window; }